diff options
Diffstat (limited to 'src/com/android/dialer/dialpad/DialpadFragment.java')
-rw-r--r-- | src/com/android/dialer/dialpad/DialpadFragment.java | 181 |
1 files changed, 137 insertions, 44 deletions
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java index 2b77b4619..f7a9056f5 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"; @@ -199,6 +221,8 @@ public class DialpadFragment extends Fragment */ private boolean mDigitsFilledByIntent; + private boolean mStartedFromNewIntent = false; + private static final String PREF_DIGITS_FILLED_BY_INTENT = "pref_digits_filled_by_intent"; /** @@ -246,14 +270,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 +295,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,7 +367,13 @@ public class DialpadFragment extends Fragment mDialpadChooser = (ListView) fragmentView.findViewById(R.id.dialpadChooser); mDialpadChooser.setOnItemClickListener(this); - configureScreenFromIntent(getActivity().getIntent()); + // 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()); + } return fragmentView; } @@ -392,45 +431,11 @@ public class DialpadFragment extends Fragment } /** - * @see #showDialpadChooser(boolean) + * Determines whether an add call operation is requested. + * + * @param intent The intent. + * @return {@literal true} if add call operation was requested. {@literal false} otherwise. */ - private static boolean needToShowDialpadChooser(Intent intent, boolean isAddCallMode) { - final String action = intent.getAction(); - - boolean needToShowDialpadChooser = false; - - if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action)) { - Uri uri = intent.getData(); - if (uri == null) { - // ACTION_DIAL or ACTION_VIEW with no data. - // This behaves basically like ACTION_MAIN: If there's - // already an active call, bring up an intermediate UI to - // make the user confirm what they really want to do. - // Be sure *not* to show the dialpad chooser if this is an - // explicit "Add call" action, though. - if (!isAddCallMode && phoneIsInUse()) { - needToShowDialpadChooser = true; - } - } - } else if (Intent.ACTION_MAIN.equals(action)) { - // The MAIN action means we're bringing up a blank dialer - // (e.g. by selecting the Home shortcut, or tabbing over from - // Contacts or Call log.) - // - // At this point, IF there's already an active call, there's a - // good chance that the user got here accidentally (but really - // wanted the in-call dialpad instead). So we bring up an - // intermediate UI to make the user confirm what they really - // want to do. - if (phoneIsInUse()) { - // Log.i(TAG, "resolveIntent(): phone is in use; showing dialpad chooser!"); - needToShowDialpadChooser = true; - } - } - - return needToShowDialpadChooser; - } - private static boolean isAddCallMode(Intent intent) { final String action = intent.getAction(); if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action)) { @@ -445,7 +450,7 @@ public class DialpadFragment extends Fragment * Checks the given Intent and changes dialpad's UI state. For example, if the Intent requires * the screen to enter "Add Call" mode, this method will show correct UI for the mode. */ - public void configureScreenFromIntent(Intent intent) { + private void configureScreenFromIntent(Intent intent) { if (!isLayoutReady()) { // This happens typically when parent's Activity#onNewIntent() is called while // Fragment#onCreateView() isn't called yet, and thus we cannot configure Views at @@ -458,16 +463,37 @@ public class DialpadFragment extends Fragment boolean needToShowDialpadChooser = false; + // Be sure *not* to show the dialpad chooser if this is an + // explicit "Add call" action, though. final boolean isAddCallMode = isAddCallMode(intent); if (!isAddCallMode) { + + // Don't show the chooser when called via onNewIntent() and phone number is present. + // i.e. User clicks a telephone link from gmail for example. + // In this case, we want to show the dialpad with the phone number. final boolean digitsFilled = fillDigitsIfNecessary(intent); - if (!digitsFilled) { - needToShowDialpadChooser = needToShowDialpadChooser(intent, isAddCallMode); + if (!(mStartedFromNewIntent && digitsFilled)) { + + final String action = intent.getAction(); + if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action) + || Intent.ACTION_MAIN.equals(action)) { + // If there's already an active call, bring up an intermediate UI to + // make the user confirm what they really want to do. + if (phoneIsInUse()) { + needToShowDialpadChooser = true; + } + } + } } + showDialpadChooser(needToShowDialpadChooser); } + public void setStartedFromNewIntent(boolean value) { + mStartedFromNewIntent = value; + } + /** * Sets formatted digits to digits field. */ @@ -501,6 +527,13 @@ public class DialpadFragment extends Fragment } @Override + public void onStart() { + super.onStart(); + configureScreenFromIntent(getActivity().getIntent()); + setStartedFromNewIntent(false); + } + + @Override public void onResume() { super.onResume(); @@ -1115,6 +1148,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 +1675,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()); + } + } } |