diff options
author | Stephen Bird <sbird@cyngn.com> | 2016-01-25 11:39:30 -0800 |
---|---|---|
committer | Stephen Bird <sbird@cyngn.com> | 2016-04-08 10:17:16 -0700 |
commit | 89368cb71de559787ae15e4c682e592c0705cc97 (patch) | |
tree | 5f3fd0bcaba8953cd5c790a2d602b607118bb61f | |
parent | 07defe6ff597d8f258c96508f000dfcd69383f31 (diff) | |
download | android_packages_apps_Dialer-89368cb71de559787ae15e4c682e592c0705cc97.tar.gz android_packages_apps_Dialer-89368cb71de559787ae15e4c682e592c0705cc97.tar.bz2 android_packages_apps_Dialer-89368cb71de559787ae15e4c682e592c0705cc97.zip |
Initial T9 search bringup
This T9 search implementation is a little different than previous
ones. It now also supports incall username searching.
Change-Id: I6d31e721aeb2e21dda4f12e8d31f7dfa539b8859
11 files changed, 307 insertions, 61 deletions
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java index a03e0cb0b..c1f39bb35 100644 --- a/src/com/android/dialer/DialtactsActivity.java +++ b/src/com/android/dialer/DialtactsActivity.java @@ -100,6 +100,7 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.phone.common.animation.AnimUtils; import com.android.phone.common.ambient.AmbientConnection; import com.android.phone.common.incall.CallMethodInfo; +import com.android.phone.common.incall.CallMethodHelper; import com.android.phone.common.util.SettingsUtil; import com.android.phone.common.animation.AnimationListenerAdapter; @@ -267,6 +268,15 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O private String mVoiceSearchQuery; private CallMethodInfo mCurrentCallMethod; + private String AMBIENT_SUBSCRIPTION_ID = "DialtactsActivity"; + + private CallMethodHelper.CallMethodReceiver pluginsUpdatedReceiver = + new CallMethodHelper.CallMethodReceiver() { + @Override + public void onChanged(HashMap<ComponentName, CallMethodInfo> callMethodInfos) { + providersUpdated(callMethodInfos); + } + }; @Override public void onCallMethodChangedListener(CallMethodInfo cmi) { @@ -293,11 +303,13 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } }; - @Override - public void onCallMethodsAvailable(HashMap<ComponentName, CallMethodInfo> availableCallMethods) { + private void providersUpdated(HashMap<ComponentName, CallMethodInfo> availableCallMethods) { if (mSmartDialSearchFragment != null) { mSmartDialSearchFragment.setAvailableCallMethods(availableCallMethods); } + // We don't want to update this until we know that our providers are loaded. otherwise + // we may miss some data. + updateSmartDialDatabase(); } protected class OptionsPopupMenu extends PopupMenu { @@ -563,7 +575,9 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O // make this call on resume in case user changed t9 locale in settings SmartDialPrefix.initializeNanpSettings(this); + } + private void updateSmartDialDatabase() { // if locale has changed since last time, refresh the smart dial db Locale locale = SettingsUtil.getT9SearchInputLocale(this); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); @@ -586,6 +600,10 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O Trace.beginSection(TAG + " onResume"); super.onResume(); + if (CallMethodHelper.subscribe(AMBIENT_SUBSCRIPTION_ID, pluginsUpdatedReceiver)) { + CallMethodHelper.refreshDynamic(); + } + mStateSaved = false; if (mFirstLaunch) { displayFragment(getIntent()); diff --git a/src/com/android/dialer/database/DialerDatabaseHelper.java b/src/com/android/dialer/database/DialerDatabaseHelper.java index f22ad7c9c..ffd0db732 100644 --- a/src/com/android/dialer/database/DialerDatabaseHelper.java +++ b/src/com/android/dialer/database/DialerDatabaseHelper.java @@ -36,6 +36,7 @@ import android.provider.ContactsContract.Directory; import android.text.TextUtils; import android.util.Log; +import com.android.contacts.common.list.PhoneNumberListAdapter; import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.StopWatch; import com.android.dialer.R; @@ -50,7 +51,9 @@ import com.google.common.collect.Lists; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -81,7 +84,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { * 0-98 KitKat * </pre> */ - public static final int DATABASE_VERSION = 70004; + public static final int DATABASE_VERSION = 70005; public static final String DATABASE_NAME = "dialer.db"; /** @@ -120,6 +123,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { static final String IN_VISIBLE_GROUP = "in_visible_group"; static final String IS_PRIMARY = "is_primary"; static final String LAST_SMARTDIAL_UPDATE_TIME = "last_smartdial_update_time"; + static final String MIMETYPE = "mimetype"; } public static interface PrefixColumns extends BaseColumns { @@ -134,7 +138,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { /** Query options for querying the contact database.*/ public static class PhoneQuery { - static final Uri URI = Phone.CONTENT_URI.buildUpon(). + static final Uri URI = ContactsContract.CommonDataKinds.Callable.CONTENT_URI.buildUpon(). appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT)). appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true"). @@ -172,6 +176,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { static final int PHONE_IS_SUPER_PRIMARY = 11; static final int PHONE_IN_VISIBLE_GROUP = 12; static final int PHONE_IS_PRIMARY = 13; + static final int PHONE_NUMBER_MIMETYPE = 14; /** Selects only rows that have been updated after a certain time stamp.*/ static final String SELECT_UPDATED_CLAUSE = @@ -262,20 +267,23 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { public final String phoneNumber; public final String lookupKey; public final long photoId; + public final String mimeType; public ContactNumber(long id, long dataID, String displayName, String phoneNumber, - String lookupKey, long photoId) { + String lookupKey, long photoId, String mimeType) { this.dataId = dataID; this.id = id; this.displayName = displayName; this.phoneNumber = phoneNumber; this.lookupKey = lookupKey; this.photoId = photoId; + this.mimeType = mimeType; } @Override public int hashCode() { - return Objects.hashCode(id, dataId, displayName, phoneNumber, lookupKey, photoId); + return Objects.hashCode(id, dataId, displayName, phoneNumber, lookupKey, photoId, + mimeType); } @Override @@ -290,7 +298,9 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { && Objects.equal(this.displayName, that.displayName) && Objects.equal(this.phoneNumber, that.phoneNumber) && Objects.equal(this.lookupKey, that.lookupKey) - && Objects.equal(this.photoId, that.photoId); + && Objects.equal(this.photoId, that.photoId) + && Objects.equal(this.mimeType, that.mimeType); + } return false; } @@ -414,7 +424,8 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { SmartDialDbColumns.STARRED + " INTEGER, " + SmartDialDbColumns.IS_SUPER_PRIMARY + " INTEGER, " + SmartDialDbColumns.IN_VISIBLE_GROUP + " INTEGER, " + - SmartDialDbColumns.IS_PRIMARY + " INTEGER" + + SmartDialDbColumns.IS_PRIMARY + " INTEGER, " + + SmartDialDbColumns.MIMETYPE + " TEXT" + ");"); db.execSQL("CREATE TABLE " + Tables.PREFIX_TABLE + " (" + @@ -725,8 +736,9 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { SmartDialDbColumns.IS_SUPER_PRIMARY + ", " + SmartDialDbColumns.IN_VISIBLE_GROUP+ ", " + SmartDialDbColumns.IS_PRIMARY + ", " + - SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + ") " + - " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + ", " + + SmartDialDbColumns.MIMETYPE + ") " + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; final SQLiteStatement insert = db.compileStatement(sqlInsert); final String numberSqlInsert = "INSERT INTO " + Tables.PREFIX_TABLE + " (" + @@ -774,11 +786,18 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { insert.bindLong(11, updatedContactCursor.getInt(PhoneQuery.PHONE_IN_VISIBLE_GROUP)); insert.bindLong(12, updatedContactCursor.getInt(PhoneQuery.PHONE_IS_PRIMARY)); insert.bindLong(13, currentMillis); + + final String mimetype = + updatedContactCursor.getString(PhoneQuery.PHONE_NUMBER_MIMETYPE); + insert.bindString(14, mimetype); + insert.executeInsert(); final String contactPhoneNumber = updatedContactCursor.getString(PhoneQuery.PHONE_NUMBER); final ArrayList<String> numberPrefixes = - SmartDialPrefix.parseToNumberTokens(contactPhoneNumber); + (TextUtils.equals(mimetype, Phone.CONTENT_ITEM_TYPE)) ? + SmartDialPrefix.parseToNumberTokens(contactPhoneNumber) : + SmartDialPrefix.generateNamePrefixes(contactPhoneNumber); for (String numberPrefix : numberPrefixes) { numberInsert.bindLong(1, updatedContactCursor.getLong( @@ -1007,7 +1026,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { * @return A list of top candidate contacts that will be suggested to user to match their input. */ public ArrayList<ContactNumber> getLooseMatches(String query, - SmartDialNameMatcher nameMatcher) { + SmartDialNameMatcher nameMatcher, String usernameMimeType) { final boolean inUpdate = sInUpdate.get(); if (inUpdate) { return Lists.newArrayList(); @@ -1031,7 +1050,8 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { SmartDialDbColumns.PHOTO_ID + ", " + SmartDialDbColumns.NUMBER + ", " + SmartDialDbColumns.CONTACT_ID + ", " + - SmartDialDbColumns.LOOKUP_KEY + + SmartDialDbColumns.LOOKUP_KEY + ", " + + SmartDialDbColumns.MIMETYPE + " FROM " + Tables.SMARTDIAL_TABLE + " ORDER BY " + SmartDialSortingOrder.SORT_ORDER, new String[] {currentTimeStamp}); @@ -1050,6 +1070,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { final int columnNumber = 3; final int columnId = 4; final int columnLookupKey = 5; + final int columnMimetype = 6; if (DEBUG) { stopWatch.lap("Found column IDs"); } @@ -1067,6 +1088,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { final long id = cursor.getLong(columnId); final long photoId = cursor.getLong(columnPhotoId); final String lookupKey = cursor.getString(columnLookupKey); + final String mimeType = cursor.getString(columnMimetype); /** If a contact already exists and another phone number of the contact is being * processed, skip the second instance. @@ -1076,18 +1098,31 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { continue; } + boolean usernameMatches = false; + if (!TextUtils.isEmpty(usernameMimeType)) { + HashMap<String, String> allCallableNumbers = getCallableMimeTypeForContact(id); + + if (allCallableNumbers.containsKey(usernameMimeType)) { + String extraContactNumber = allCallableNumbers.get(usernameMimeType); + if (extraContactNumber != null) { + usernameMatches = nameMatcher.matches(extraContactNumber); + } + } + + } + /** - * If the contact has either the name or number that matches the query, add to the - * result. + * If the contact has either the name or number OR a username + * that matches the query, add to the result. */ final boolean nameMatches = nameMatcher.matches(displayName); final boolean numberMatches = (nameMatcher.matchesNumber(phoneNumber, query) != null); - if (nameMatches || numberMatches) { + if (nameMatches || numberMatches || usernameMatches) { /** If a contact has not been added, add it to the result and the hash set.*/ duplicates.add(contactMatch); result.add(new ContactNumber(id, dataID, displayName, phoneNumber, lookupKey, - photoId)); + photoId, mimeType)); counter++; if (DEBUG) { stopWatch.lap("Added one result: Name: " + displayName); @@ -1103,4 +1138,41 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper { } return result; } + + public HashMap<String, String> getCallableMimeTypeForContact(long contactId) { + final SQLiteDatabase db = getReadableDatabase(); + + final Cursor cursor = db.rawQuery("SELECT " + + SmartDialDbColumns.NUMBER + ", " + + SmartDialDbColumns.MIMETYPE + + " FROM " + Tables.SMARTDIAL_TABLE + + " WHERE " + SmartDialDbColumns.CONTACT_ID + " = ?", + new String[] {Long.toString(contactId)}); + + try { + if (cursor != null) { + HashMap<String, String> numbers = new HashMap<>(); + while(cursor.moveToNext()) { + + /** Gets the column ID from the cursor.*/ + final int columnNumber = 0; + final int columnMimetype = 1; + + final String phoneNumber = cursor.getString(columnNumber); + final String mimetype = cursor.getString(columnMimetype); + + if (phoneNumber != null) { + numbers.put(mimetype, phoneNumber); + } + } + return numbers; + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return null; + } } diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java index b90e54bc5..d9fcbf059 100644 --- a/src/com/android/dialer/dialpad/DialpadFragment.java +++ b/src/com/android/dialer/dialpad/DialpadFragment.java @@ -150,7 +150,6 @@ public class DialpadFragment extends Fragment public interface OnCallMethodChangedListener { void onCallMethodChangedListener(CallMethodInfo cmi); - void onCallMethodsAvailable(HashMap<ComponentName, CallMethodInfo> availableProviders); } public interface HostInterface { @@ -544,7 +543,6 @@ public class DialpadFragment extends Fragment private void providersUpdated(HashMap<ComponentName, CallMethodInfo> callMethodInfos) { mAllAvailableProviders.clear(); CallMethodHelper.removeDisabled(callMethodInfos, mAllAvailableProviders); - mCallMethodChangedListener.onCallMethodsAvailable(mAllAvailableProviders); updateCallMethodSpinner(); } diff --git a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java index 0a8c22370..fcfe3ae09 100644 --- a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java +++ b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java @@ -17,20 +17,28 @@ package com.android.dialer.dialpad; import android.content.AsyncTaskLoader; +import android.content.ContentUris; import android.content.Context; import android.content.Loader.ForceLoadContentObserver; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; +import android.provider.ContactsContract; +import android.text.TextUtils; import android.util.Log; import com.android.contacts.common.list.PhoneNumberListAdapter.PhoneQuery; import com.android.contacts.common.util.PermissionsUtil; + +import com.android.phone.common.incall.CallMethodHelper; + import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.database.DialerDatabaseHelper.ContactNumber; import com.android.dialerbind.DatabaseHelperManager; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; /** * Implements a Loader<Cursor> class to asynchronously load SmartDial search results. @@ -49,6 +57,9 @@ public class SmartDialCursorLoader extends AsyncTaskLoader<Cursor> { private ForceLoadContentObserver mObserver; + private String mCallableMimetype; + public static final String CALLABLE_EXTRA_NUMBER = "callable_extra_number"; + public SmartDialCursorLoader(Context context) { super(context); mContext = context; @@ -58,7 +69,7 @@ public class SmartDialCursorLoader extends AsyncTaskLoader<Cursor> { * Configures the query string to be used to find SmartDial matches. * @param query The query string user typed. */ - public void configureQuery(String query) { + public void configureQuery(String query, String callableMimetype) { if (DEBUG) { Log.v(TAG, "Configure new query to be " + query); } @@ -66,6 +77,7 @@ public class SmartDialCursorLoader extends AsyncTaskLoader<Cursor> { /** Constructs a name matcher object for matching names. */ mNameMatcher = new SmartDialNameMatcher(mQuery, SmartDialPrefix.getMap(), mContext); + mCallableMimetype = callableMimetype; } /** @@ -86,23 +98,84 @@ public class SmartDialCursorLoader extends AsyncTaskLoader<Cursor> { final DialerDatabaseHelper dialerDatabaseHelper = DatabaseHelperManager.getDatabaseHelper( mContext); final ArrayList<ContactNumber> allMatches = dialerDatabaseHelper.getLooseMatches(mQuery, - mNameMatcher); + mNameMatcher, mCallableMimetype); if (DEBUG) { Log.v(TAG, "Loaded matches " + String.valueOf(allMatches.size())); } + int projectionLength = PhoneQuery.PROJECTION_PRIMARY.length; + String [] projection = new String[projectionLength + 1]; + System.arraycopy(PhoneQuery.PROJECTION_PRIMARY, 0, projection, 0, projectionLength); + projection[projectionLength] = CALLABLE_EXTRA_NUMBER; + /** Constructs a cursor for the returned array of results. */ - final MatrixCursor cursor = new MatrixCursor(PhoneQuery.PROJECTION_PRIMARY); - Object[] row = new Object[PhoneQuery.PROJECTION_PRIMARY.length]; + final MatrixCursor cursor = new MatrixCursor(projection); + Object[] row = new Object[projectionLength + 1]; for (ContactNumber contact : allMatches) { - row[PhoneQuery.PHONE_ID] = contact.dataId; - row[PhoneQuery.PHONE_NUMBER] = contact.phoneNumber; - row[PhoneQuery.CONTACT_ID] = contact.id; - row[PhoneQuery.LOOKUP_KEY] = contact.lookupKey; - row[PhoneQuery.PHOTO_ID] = contact.photoId; - row[PhoneQuery.DISPLAY_NAME] = contact.displayName; - cursor.addRow(row); + if (TextUtils.equals(contact.mimeType, mCallableMimetype) || + TextUtils.equals(contact.mimeType, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) { + row[PhoneQuery.CONTACT_ID] = contact.id; + row[PhoneQuery.LOOKUP_KEY] = contact.lookupKey; + row[PhoneQuery.PHOTO_ID] = contact.photoId; + row[PhoneQuery.DISPLAY_NAME] = contact.displayName; + row[PhoneQuery.PHONE_ID] = contact.dataId; + + // The row object is resued, so explicitly set this to null in case the contact + // doesn't have extra numbers + row[projectionLength] = null; + + String accountType = null; + String accountName = null; + Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, + contact.id); + Cursor c = mContext.getContentResolver().query( + contactUri, + new String[]{ContactsContract.RawContacts.ACCOUNT_TYPE, + ContactsContract.RawContacts.ACCOUNT_NAME}, + null, null, null); + if (c != null && c.moveToFirst()) { + accountType = c.getString(0); + accountName = c.getString(1); + c.close(); + } + row[PhoneQuery.PHONE_ACCOUNT_TYPE] = accountType; + row[PhoneQuery.PHONE_ACCOUNT_NAME] = accountName; + + HashMap<String, String> allCallableNumbers = dialerDatabaseHelper + .getCallableMimeTypeForContact(contact.id); + + // Add the phone number as the primary option ALWAYS + // IF we don't do this, things often show up strange (only a UN w/o PN) + // if the user has no phone number tied to their account, then we can show other + // items. We do this for consistencies sake. + String extraContactNumber; + boolean gotStandardNumber = false; + if (allCallableNumbers.containsKey(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) { + extraContactNumber = allCallableNumbers.get(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE); + + row[PhoneQuery.PHONE_NUMBER] = extraContactNumber; + row[PhoneQuery.PHONE_MIME_TYPE] = + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE; + + gotStandardNumber = true; + } + + if (allCallableNumbers.containsKey(mCallableMimetype)) { + extraContactNumber = allCallableNumbers.get(mCallableMimetype); + // Make sure the extra number is not the same as the main number + if (gotStandardNumber) { + row[projectionLength] = extraContactNumber; + } else { + row[PhoneQuery.PHONE_NUMBER] = extraContactNumber; + row[PhoneQuery.PHONE_MIME_TYPE] = mCallableMimetype; + } + } + + + cursor.addRow(row); + } } return cursor; } diff --git a/src/com/android/dialer/dialpad/SmartDialNameMatcher.java b/src/com/android/dialer/dialpad/SmartDialNameMatcher.java index 4daf0c837..38ee947cd 100644 --- a/src/com/android/dialer/dialpad/SmartDialNameMatcher.java +++ b/src/com/android/dialer/dialpad/SmartDialNameMatcher.java @@ -261,6 +261,11 @@ public class SmartDialNameMatcher { @VisibleForTesting boolean matchesCombination(String displayName, String query, ArrayList<SmartDialMatchPosition> matchList) { + + if (displayName == null) { + return false; + } + StringBuilder builder = new StringBuilder(); constructEmptyMask(builder, displayName.length()); mNameMatchMask = builder.toString(); diff --git a/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java b/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java index 401b0b641..0ca8e56f6 100644 --- a/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java +++ b/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java @@ -5,9 +5,11 @@ import android.content.res.Resources; import android.telephony.PhoneNumberUtils; import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; +import android.util.Log; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import com.android.contacts.common.GeoUtil; import com.android.contacts.common.list.ContactListItemView; import com.android.contacts.common.list.PhoneNumberListAdapter; @@ -27,25 +29,35 @@ public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter { private String mFormattedQueryString; private String mCountryIso; + public final static int SHORTCUT_INVALID_PROVIDER = -2; public final static int SHORTCUT_INVALID = -1; public final static int SHORTCUT_DIRECT_CALL = 0; public final static int SHORTCUT_CREATE_NEW_CONTACT = 1; public final static int SHORTCUT_ADD_TO_EXISTING_CONTACT = 2; public final static int SHORTCUT_SEND_SMS_MESSAGE = 3; public final static int SHORTCUT_MAKE_VIDEO_CALL = 4; + public final static int SHORTCUT_MAKE_INCALL_PROVIDER_CALL = 5; - public final static int SHORTCUT_COUNT = 5; + public static int SHORTCUT_COUNT = 6; private final boolean[] mShortcutEnabled = new boolean[SHORTCUT_COUNT]; + private int mShortcutCurrent = SHORTCUT_INVALID; + private final BidiFormatter mBidiFormatter = BidiFormatter.getInstance(); + private searchMethodClicked mSearchMethodListener = null; + public DialerPhoneNumberListAdapter(Context context) { super(context); mCountryIso = GeoUtil.getCurrentCountryIso(context); } + public void setSearchListner(searchMethodClicked clickedListener) { + mSearchMethodListener = clickedListener; + } + @Override public int getCount() { return super.getCount() + getShortcutCount(); @@ -121,7 +133,11 @@ public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter { throw new IllegalArgumentException("Invalid position - greater than cursor count " + " but not a shortcut."); } - return SHORTCUT_INVALID; + + int returningShortcut = mShortcutCurrent; + mShortcutCurrent = SHORTCUT_INVALID; + + return returningShortcut; } @Override @@ -167,6 +183,12 @@ public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter { text = resources.getString(R.string.search_shortcut_make_video_call); drawableId = R.drawable.ic_videocam; break; + case SHORTCUT_MAKE_INCALL_PROVIDER_CALL: + text = resources.getString( + R.string.search_shortcut_call_number, + mBidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR)); + drawableId = R.drawable.ic_videocam; + break; default: throw new IllegalArgumentException("Invalid shortcut type"); } @@ -176,6 +198,22 @@ public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter { v.setAdjustSelectionBoundsEnabled(false); } + public interface searchMethodClicked { + void onItemClick(int position, long id); + } + + @Override + public View.OnClickListener bindExtraCallActionOnClick(TextView v, String text, + final int position) { + return new View.OnClickListener() { + @Override + public void onClick(View view) { + mShortcutCurrent = SHORTCUT_INVALID_PROVIDER; + mSearchMethodListener.onItemClick(position, 0L); + } + }; + } + /** * @return True if the shortcut state (disabled vs enabled) was changed by this operation */ diff --git a/src/com/android/dialer/list/RegularSearchListAdapter.java b/src/com/android/dialer/list/RegularSearchListAdapter.java index 944fec64f..fe5040f3a 100644 --- a/src/com/android/dialer/list/RegularSearchListAdapter.java +++ b/src/com/android/dialer/list/RegularSearchListAdapter.java @@ -104,6 +104,8 @@ public class RegularSearchListAdapter extends DialerPhoneNumberListAdapter { changed |= setShortcutEnabled(SHORTCUT_SEND_SMS_MESSAGE, showNumberShortcuts); changed |= setShortcutEnabled(SHORTCUT_MAKE_VIDEO_CALL, showNumberShortcuts && CallUtil.isVideoEnabled(getContext())); + changed |= setShortcutEnabled(SHORTCUT_MAKE_INCALL_PROVIDER_CALL, showNumberShortcuts); + if (changed) { notifyDataSetChanged(); } diff --git a/src/com/android/dialer/list/SearchFragment.java b/src/com/android/dialer/list/SearchFragment.java index 9f9ea7bb6..eb5c13bd1 100644 --- a/src/com/android/dialer/list/SearchFragment.java +++ b/src/com/android/dialer/list/SearchFragment.java @@ -54,8 +54,10 @@ import com.android.dialer.util.DialerUtils; import com.android.dialer.util.IntentUtil; import com.android.dialer.widget.EmptyContentView; import com.android.phone.common.animation.AnimUtils; +import com.android.phone.common.incall.CallMethodInfo; -public class SearchFragment extends PhoneNumberPickerFragment { +public class SearchFragment extends PhoneNumberPickerFragment + implements DialerPhoneNumberListAdapter.searchMethodClicked { private static final String TAG = SearchFragment.class.getSimpleName(); private OnListFragmentScrolledListener mActivityScrollListener; @@ -84,6 +86,8 @@ public class SearchFragment extends PhoneNumberPickerFragment { protected EmptyContentView mEmptyView; + public CallMethodInfo mCurrentCallMethodInfo; + public interface HostInterface { public boolean isActionBarShowing(); public boolean isDialpadShown(); @@ -229,13 +233,15 @@ public class SearchFragment extends PhoneNumberPickerFragment { DialerPhoneNumberListAdapter adapter = new DialerPhoneNumberListAdapter(getActivity()); adapter.setDisplayPhotos(true); adapter.setUseCallableUri(super.usesCallableUri()); + adapter.setSearchListner(this); return adapter; } @Override - protected void onItemClick(int position, long id) { + public void onItemClick(int position, long id) { final DialerPhoneNumberListAdapter adapter = (DialerPhoneNumberListAdapter) getAdapter(); final int shortcutType = adapter.getShortcutTypeFromPosition(position); + final OnPhoneNumberPickerActionListener listener; final Intent intent; final String number; @@ -243,6 +249,9 @@ public class SearchFragment extends PhoneNumberPickerFragment { Log.i(TAG, "onItemClick: shortcutType=" + shortcutType); switch (shortcutType) { + case DialerPhoneNumberListAdapter.SHORTCUT_INVALID_PROVIDER: + super.onProviderClick(position, id, getCurrentCallMethod()); + break; case DialerPhoneNumberListAdapter.SHORTCUT_INVALID: super.onItemClick(position, id); break; @@ -283,6 +292,15 @@ public class SearchFragment extends PhoneNumberPickerFragment { } } + public void setCurrentCallMethod(CallMethodInfo cmi) { + mCurrentCallMethodInfo = cmi; + setupEmptyView(); + } + + public CallMethodInfo getCurrentCallMethod() { + return mCurrentCallMethodInfo; + } + /** * Updates the position and padding of the search fragment, depending on whether the dialpad is * shown. This can be optionally animated. @@ -355,7 +373,7 @@ public class SearchFragment extends PhoneNumberPickerFragment { @Override protected void startLoading() { - if (PermissionsUtil.hasPermission(getActivity(), READ_CONTACTS)) { + if (isAdded() && PermissionsUtil.hasPermission(getActivity(), READ_CONTACTS)) { super.startLoading(); } else if (TextUtils.isEmpty(getQueryString())) { // Clear out any existing call shortcuts. diff --git a/src/com/android/dialer/list/SmartDialNumberListAdapter.java b/src/com/android/dialer/list/SmartDialNumberListAdapter.java index 5563b0f91..00dbd017b 100644 --- a/src/com/android/dialer/list/SmartDialNumberListAdapter.java +++ b/src/com/android/dialer/list/SmartDialNumberListAdapter.java @@ -44,6 +44,7 @@ public class SmartDialNumberListAdapter extends DialerPhoneNumberListAdapter { private final Context mContext; private SmartDialNameMatcher mNameMatcher; + SmartDialCursorLoader mLoader; public SmartDialNumberListAdapter(Context context) { super(context); @@ -55,10 +56,15 @@ public class SmartDialNumberListAdapter extends DialerPhoneNumberListAdapter { } } + public SmartDialCursorLoader getLoader() { + return mLoader; + } + /** * Sets query for the SmartDialCursorLoader. */ - public void configureLoader(SmartDialCursorLoader loader) { + public void configureLoader(SmartDialCursorLoader loader, String mimeType) { + mLoader = loader; if (DEBUG) { Log.v(TAG, "Configure Loader with query" + getQueryString()); } @@ -66,10 +72,10 @@ public class SmartDialNumberListAdapter extends DialerPhoneNumberListAdapter { mNameMatcher = new SmartDialNameMatcher("", SmartDialPrefix.getMap(), mContext); if (getQueryString() == null) { - loader.configureQuery(""); + mLoader.configureQuery("", mimeType); mNameMatcher.setQuery(""); } else { - loader.configureQuery(getQueryString()); + mLoader.configureQuery(getQueryString(), mimeType); mNameMatcher.setQuery(PhoneNumberUtils.normalizeNumber(getQueryString())); } } @@ -126,6 +132,8 @@ public class SmartDialNumberListAdapter extends DialerPhoneNumberListAdapter { changed |= setShortcutEnabled(SHORTCUT_SEND_SMS_MESSAGE, showNumberShortcuts); changed |= setShortcutEnabled(SHORTCUT_MAKE_VIDEO_CALL, showNumberShortcuts && CallUtil.isVideoEnabled(getContext())); + changed |= setShortcutEnabled(SHORTCUT_MAKE_INCALL_PROVIDER_CALL, showNumberShortcuts); + if (changed) { notifyDataSetChanged(); } diff --git a/src/com/android/dialer/list/SmartDialSearchFragment.java b/src/com/android/dialer/list/SmartDialSearchFragment.java index 6d638e323..08fc2be27 100644 --- a/src/com/android/dialer/list/SmartDialSearchFragment.java +++ b/src/com/android/dialer/list/SmartDialSearchFragment.java @@ -57,12 +57,12 @@ import java.util.Random; * Implements a fragment to load and display SmartDial search results. */ public class SmartDialSearchFragment extends SearchFragment - implements EmptyContentView.OnEmptyViewActionButtonClickedListener { + implements EmptyContentView.OnEmptyViewActionButtonClickedListener, + DialerPhoneNumberListAdapter.searchMethodClicked { private static final String TAG = SmartDialSearchFragment.class.getSimpleName(); private static final int CALL_PHONE_PERMISSION_REQUEST_CODE = 1; - private CallMethodInfo mCurrentCallMethod; private HashMap<ComponentName, CallMethodInfo> mAvailableCallMethods; /** @@ -75,6 +75,8 @@ public class SmartDialSearchFragment extends SearchFragment adapter.setQuickContactEnabled(true); // Set adapter's query string to restore previous instance state. adapter.setQueryString(getQueryString()); + adapter.setSearchListner(this); + return adapter; } @@ -87,10 +89,7 @@ public class SmartDialSearchFragment extends SearchFragment if (id == getDirectoryLoaderId()) { return super.onCreateLoader(id, args); } else { - final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter(); - SmartDialCursorLoader loader = new SmartDialCursorLoader(super.getContext()); - adapter.configureLoader(loader); - return loader; + return updateData(); } } @@ -105,13 +104,27 @@ public class SmartDialSearchFragment extends SearchFragment return adapter.getDataUri(position); } + private Loader<Cursor> updateData() { + final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter(); + + SmartDialCursorLoader loader = new SmartDialCursorLoader(super.getContext()); + + if (mCurrentCallMethodInfo != null) { + adapter.configureLoader(loader, mCurrentCallMethodInfo.mMimeType); + } else { + adapter.configureLoader(loader, null); + } + + return loader; + } + @Override public void setupEmptyView() { final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter(); adapter.getCount(); - if (mCurrentCallMethod == null) { - mCurrentCallMethod = ((DialtactsActivity) getActivity()).getCurrentCallMethod(); + if (mCurrentCallMethodInfo == null) { + mCurrentCallMethodInfo = ((DialtactsActivity) getActivity()).getCurrentCallMethod(); } if (mEmptyView != null && getActivity() != null) { @@ -130,10 +143,10 @@ public class SmartDialSearchFragment extends SearchFragment // the currently available ones are fine. mAvailableCallMethods = CallMethodHelper.getAllCallMethods(); - if (mCurrentCallMethod == null && mAvailableCallMethods.isEmpty()) { + if (mCurrentCallMethodInfo == null && mAvailableCallMethods.isEmpty()) { showNormalT9Hint(r); } else { - if (mCurrentCallMethod != null && mCurrentCallMethod.mIsInCallProvider) { + if (mCurrentCallMethodInfo != null && mCurrentCallMethodInfo.mIsInCallProvider) { showProviderHint(r); } else { showSuggestion(r); @@ -165,14 +178,14 @@ public class SmartDialSearchFragment extends SearchFragment public void showProviderHint(Resources r) { String text; - if (!mCurrentCallMethod.mIsAuthenticated) { + if (!mCurrentCallMethodInfo.mIsAuthenticated) { // Sign into current selected call method to make calls - text = getString(R.string.sign_in_hint_text, mCurrentCallMethod.mName); + text = getString(R.string.sign_in_hint_text, mCurrentCallMethodInfo.mName); } else { // InCallApi provider specified hint - text = mCurrentCallMethod.mT9HintDescription; + text = mCurrentCallMethodInfo.mT9HintDescription; } - Drawable heroImage = mCurrentCallMethod.mSingleColorBrandIcon; + Drawable heroImage = mCurrentCallMethodInfo.mSingleColorBrandIcon; heroImage.setTint(r.getColor(R.color.hint_image_color)); mEmptyView.setImage(heroImage); mEmptyView.setDescription(text); @@ -186,17 +199,17 @@ public class SmartDialSearchFragment extends SearchFragment NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); - if (mWifi.isConnected() && !mAvailableCallMethods.isEmpty() && mCurrentCallMethod != null) { + if (mWifi.isConnected() && !mAvailableCallMethods.isEmpty() && mCurrentCallMethodInfo != null) { String template; Drawable heroImage; String text; TelephonyManager tm = (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); - if (tm.isNetworkRoaming(mCurrentCallMethod.mSubId)) { + if (tm.isNetworkRoaming(mCurrentCallMethodInfo.mSubId)) { heroImage = r.getDrawable(R.drawable.ic_roaming); template = r.getString(R.string.roaming_hint_text); - text = String.format(template, mCurrentCallMethod.mName, hintTextRequest()); + text = String.format(template, mCurrentCallMethodInfo.mName, hintTextRequest()); } else { heroImage = r.getDrawable(R.drawable.ic_signal_wifi_3_bar); template = r.getString(R.string.wifi_hint_text); @@ -219,9 +232,10 @@ public class SmartDialSearchFragment extends SearchFragment return valuesList.get(randomIndex).mName; } + @Override public void setCurrentCallMethod(CallMethodInfo cmi) { - mCurrentCallMethod = cmi; - setupEmptyView(); + super.setCurrentCallMethod(cmi); + reloadData(); } public void setAvailableCallMethods(HashMap<ComponentName, CallMethodInfo> callMethods) { diff --git a/tests/src/com/android/dialer/database/SmartDialPrefixTest.java b/tests/src/com/android/dialer/database/SmartDialPrefixTest.java index 796303d78..4588ac727 100644 --- a/tests/src/com/android/dialer/database/SmartDialPrefixTest.java +++ b/tests/src/com/android/dialer/database/SmartDialPrefixTest.java @@ -137,13 +137,13 @@ public class SmartDialPrefixTest extends AndroidTestCase { private ContactNumber constructNewContactWithDummyIds(MatrixCursor contactCursor, MatrixCursor nameCursor, String number, int id, String displayName) { return constructNewContact(contactCursor, nameCursor, id, number, id, String.valueOf(id), - displayName, 0, 0, 0, 0, 0, 0, 0); + displayName, 0, 0, 0, 0, 0, 0, 0, null); } private ContactNumber constructNewContact(MatrixCursor contactCursor, MatrixCursor nameCursor, int id, String number, int contactId, String lookupKey, String displayName, int photoId, int lastTimeUsed, int timesUsed, int starred, int isSuperPrimary, int inVisibleGroup, - int isPrimary) { + int isPrimary, String mimetype) { assertNotNull(contactCursor); assertNotNull(nameCursor); @@ -158,13 +158,13 @@ public class SmartDialPrefixTest extends AndroidTestCase { isPrimary}); nameCursor.addRow(new Object[]{displayName, contactId}); - return new ContactNumber(contactId, id, displayName, number, lookupKey, 0); + return new ContactNumber(contactId, id, displayName, number, lookupKey, 0, mimetype); } private ArrayList<ContactNumber> getLooseMatchesFromDb(String query) { final SmartDialNameMatcher nameMatcher = new SmartDialNameMatcher(query, SmartDialPrefix.getMap(), getContext()); - return mTestHelper.getLooseMatches(query, nameMatcher); + return mTestHelper.getLooseMatches(query, nameMatcher, null); } public void testPutForFullName() { |