diff options
author | Yorke Lee <yorkelee@google.com> | 2012-11-07 15:11:44 -0800 |
---|---|---|
committer | Yorke Lee <yorkelee@google.com> | 2012-11-07 15:50:04 -0800 |
commit | 1be0178a11b1cc3b06867b14446e1e041e97a82c (patch) | |
tree | 90d972b1c98ce31fee597ba57461741266c0149f /src/com/android/dialer/dialpad/DialpadFragment.java | |
parent | 90a85b2201a3e1132124827714ee34e00091036f (diff) |
Add smart dialling capabilities to dialer
Layout changes to dialpad fragment to make space for smart dial suggestions.
This feature does not appear in landscape mode.
SmartDialTextView automatically resizes text to fit within the bounds of the view.
SmartDialAdapter highlights certain portions of the matching name based on match
positions provided by SmartDialNameMatcher.
SmartDialLoaderTask is an AsyncTask that caches all contacts with a phone number
into memory, or matches all contact names against a provided query to return a
list of matches (maximum of 3).
SmartDialNameMatcher contains utility functions to remove accents from accented
characters and normalize a phone number. It also contains the matching logic that
determines if a contact's display name matches a numeric query.
Added some tests for SmartDialNameMatcher
Bug: 6977981
Change-Id: I43e1a70d8d0d46e02fc67fe1caaec9a1769124f5
Diffstat (limited to 'src/com/android/dialer/dialpad/DialpadFragment.java')
-rw-r--r-- | src/com/android/dialer/dialpad/DialpadFragment.java | 103 |
1 files changed, 101 insertions, 2 deletions
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java index 2b77b4619..3af7f9bec 100644 --- a/src/com/android/dialer/dialpad/DialpadFragment.java +++ b/src/com/android/dialer/dialpad/DialpadFragment.java @@ -31,6 +31,7 @@ import android.graphics.BitmapFactory; import android.media.AudioManager; import android.media.ToneGenerator; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -39,6 +40,7 @@ import android.provider.Contacts.Intents.Insert; import android.provider.Contacts.People; import android.provider.Contacts.Phones; import android.provider.Contacts.PhonesColumns; +import android.provider.ContactsContract.Contacts; import android.provider.Settings; import android.telephony.PhoneNumberUtils; import android.telephony.PhoneStateListener; @@ -59,6 +61,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; +import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.EditText; @@ -68,9 +71,12 @@ import android.widget.PopupMenu; import android.widget.TextView; import com.android.contacts.common.CallUtil; +import com.android.contacts.common.activity.TransactionSafeActivity; +import com.android.dialer.interactions.PhoneNumberInteraction; import com.android.contacts.common.GeoUtil; import com.android.contacts.common.util.PhoneNumberFormatter; import com.android.contacts.common.util.StopWatch; +import com.android.contacts.common.preference.ContactsPreferences; import com.android.dialer.DialtactsActivity; import com.android.dialer.R; import com.android.dialer.SpecialCharSequenceMgr; @@ -79,6 +85,9 @@ import com.android.internal.telephony.ITelephony; import com.android.phone.common.CallLogAsync; import com.android.phone.common.HapticFeedback; +import java.util.ArrayList; +import java.util.List; + /** * Fragment that displays a twelve-key phone dialpad. */ @@ -87,7 +96,8 @@ public class DialpadFragment extends Fragment View.OnLongClickListener, View.OnKeyListener, AdapterView.OnItemClickListener, TextWatcher, PopupMenu.OnMenuItemClickListener, - DialpadImageButton.OnPressedListener { + DialpadImageButton.OnPressedListener, + SmartDialLoaderTask.SmartDialLoaderCallback { private static final String TAG = DialpadFragment.class.getSimpleName(); private static final boolean DEBUG = DialtactsActivity.DEBUG; @@ -104,6 +114,8 @@ public class DialpadFragment extends Fragment /** Stream type used to play the DTMF tones off call, and mapped to the volume control keys */ private static final int DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_DTMF; + private ContactsPreferences mContactsPrefs; + /** * View (usually FrameLayout) containing mDigits field. This can be null, in which mDigits * isn't enclosed by the container. @@ -131,6 +143,15 @@ public class DialpadFragment extends Fragment private ListView mDialpadChooser; private DialpadChooserAdapter mDialpadChooserAdapter; + /** Will be set only if the view has the smart dialing section. */ + private AbsListView mSmartDialList; + + /** + * Adapter for {@link #mSmartDialList}. + * Will be set only if the view has the smart dialing section. + */ + private SmartDialAdapter mSmartDialAdapter; + /** * Regular expression prohibiting manual phone call. Can be empty, which means "no rule". */ @@ -149,6 +170,7 @@ public class DialpadFragment extends Fragment // Vibration (haptic feedback) for dialer key presses. private final HapticFeedback mHaptic = new HapticFeedback(); + private boolean mNeedToCacheSmartDial = false; /** Identifier for the "Add Call" intent extra. */ private static final String ADD_CALL_MODE_KEY = "add_call_mode"; @@ -246,14 +268,16 @@ public class DialpadFragment extends Fragment } updateDialAndDeleteButtonEnabledState(); + loadSmartDialEntries(); } @Override public void onCreate(Bundle state) { super.onCreate(state); + mContactsPrefs = new ContactsPreferences(getActivity()); mCurrentCountryIso = GeoUtil.getCurrentCountryIso(getActivity()); - + mNeedToCacheSmartDial = true; try { mHaptic.init(getActivity(), getResources().getBoolean(R.bool.config_enable_dialer_key_vibration)); @@ -269,6 +293,13 @@ public class DialpadFragment extends Fragment if (state != null) { mDigitsFilledByIntent = state.getBoolean(PREF_DIGITS_FILLED_BY_INTENT); } + + // Start caching contacts to use for smart dialling only if the dialpad fragment is visible + if (getUserVisibleHint()) { + SmartDialLoaderTask.startCacheContactsTaskIfNeeded( + getActivity(), mContactsPrefs.getDisplayOrder()); + mNeedToCacheSmartDial = false; + } } @Override @@ -334,6 +365,14 @@ public class DialpadFragment extends Fragment mDialpadChooser = (ListView) fragmentView.findViewById(R.id.dialpadChooser); mDialpadChooser.setOnItemClickListener(this); + // Smart dial + mSmartDialList = (AbsListView) fragmentView.findViewById(R.id.dialpad_smartdial_list); + if (mSmartDialList != null) { + mSmartDialAdapter = new SmartDialAdapter(getActivity()); + mSmartDialList.setAdapter(mSmartDialAdapter); + mSmartDialList.setOnItemClickListener(new OnSmartDialItemClick()); + } + configureScreenFromIntent(getActivity().getIntent()); return fragmentView; @@ -1115,6 +1154,11 @@ public class DialpadFragment extends Fragment } } + private String getCallOrigin() { + return (getActivity() instanceof DialtactsActivity) ? + ((DialtactsActivity) getActivity()).getCallOrigin() : null; + } + private void handleDialButtonClickWithEmptyDigits() { if (phoneIsCdma() && phoneIsOffhook()) { // This is really CDMA specific. On GSM is it possible @@ -1637,4 +1681,59 @@ public class DialpadFragment extends Fragment intent.putExtra(EXTRA_SEND_EMPTY_FLASH, true); return intent; } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (isVisibleToUser && mNeedToCacheSmartDial) { + SmartDialLoaderTask.startCacheContactsTaskIfNeeded( + getActivity(), mContactsPrefs.getDisplayOrder()); + mNeedToCacheSmartDial = false; + } + } + + private String mLastDigitsForSmartDial; + + private void loadSmartDialEntries() { + if (mSmartDialAdapter == null) { + // No smart dial views. Landscape? + return; + } + + // Update only when the digits have changed. + final String digits = SmartDialNameMatcher.normalizeNumber(mDigits.getText().toString()); + if (TextUtils.equals(digits, mLastDigitsForSmartDial)) { + return; + } + mLastDigitsForSmartDial = digits; + + if (digits.length() < 2) { + mSmartDialAdapter.clear(); + } else { + final SmartDialLoaderTask task = new SmartDialLoaderTask(this, digits); + // don't execute this in serial, otherwise we have to wait too long for results + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[] {}); + } + } + + @Override + public void setSmartDialAdapterEntries(List<SmartDialEntry> data) { + if (data == null || data.isEmpty()) { + // No results found. Keep the last results. + return; + } + mSmartDialAdapter.setEntries(data); + } + + private class OnSmartDialItemClick implements AdapterView.OnItemClickListener { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + final SmartDialEntry entry = (SmartDialEntry) view.getTag(); + if (entry == null) return; // just in case. + + mClearDigitsOnStop = true; + PhoneNumberInteraction.startInteractionForPhoneCall( + (TransactionSafeActivity) getActivity(), entry.contactUri, getCallOrigin()); + } + } } |