summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/searchfragment
diff options
context:
space:
mode:
authorlinyuh <linyuh@google.com>2017-11-02 18:05:33 -0700
committerzachh <zachh@google.com>2017-11-11 06:38:23 +0000
commit82670fee34bfc922905f31d3904406eb0677b162 (patch)
tree69c66cb89539c970896a3d16fcf347ad1ee47c7f /java/com/android/dialer/searchfragment
parent83d8a62ee2b2262941590ff5ef35986dc1df1fa1 (diff)
Support dual alphabets in smart search when a secondary alphabet is available.
Bug: 30215380 Test: QueryBoldingUtilTest, QueryFilteringUtilTest, ContactFilterCursorTest PiperOrigin-RevId: 174408771 Change-Id: I4c601b16dd90db6b7b2a05c9daa6804749ea2a43
Diffstat (limited to 'java/com/android/dialer/searchfragment')
-rw-r--r--java/com/android/dialer/searchfragment/common/QueryBoldingUtil.java17
-rw-r--r--java/com/android/dialer/searchfragment/common/QueryFilteringUtil.java101
-rw-r--r--java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java12
-rw-r--r--java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java2
-rw-r--r--java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java10
-rw-r--r--java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java2
-rw-r--r--java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java4
-rw-r--r--java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java4
8 files changed, 86 insertions, 66 deletions
diff --git a/java/com/android/dialer/searchfragment/common/QueryBoldingUtil.java b/java/com/android/dialer/searchfragment/common/QueryBoldingUtil.java
index 4413252f4..9ac6e7c5e 100644
--- a/java/com/android/dialer/searchfragment/common/QueryBoldingUtil.java
+++ b/java/com/android/dialer/searchfragment/common/QueryBoldingUtil.java
@@ -16,6 +16,7 @@
package com.android.dialer.searchfragment.common;
+import android.content.Context;
import android.graphics.Typeface;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -49,14 +50,16 @@ public class QueryBoldingUtil {
*
* @param query containing any characters
* @param name of a contact/string that query will compare to
+ * @param context of the app
* @return name with query bolded if query can be found in the name.
*/
- public static CharSequence getNameWithQueryBolded(@Nullable String query, @NonNull String name) {
+ public static CharSequence getNameWithQueryBolded(
+ @Nullable String query, @NonNull String name, @NonNull Context context) {
if (TextUtils.isEmpty(query)) {
return name;
}
- if (!QueryFilteringUtil.nameMatchesT9Query(query, name)) {
+ if (!QueryFilteringUtil.nameMatchesT9Query(query, name, context)) {
Pattern pattern = Pattern.compile("(^|\\s)" + Pattern.quote(query.toLowerCase()));
Matcher matcher = pattern.matcher(name.toLowerCase());
if (matcher.find()) {
@@ -69,7 +72,7 @@ public class QueryBoldingUtil {
}
Pattern pattern = Pattern.compile("(^|\\s)" + Pattern.quote(query.toLowerCase()));
- Matcher matcher = pattern.matcher(QueryFilteringUtil.getT9Representation(name));
+ Matcher matcher = pattern.matcher(QueryFilteringUtil.getT9Representation(name, context));
if (matcher.find()) {
// query matches the start of a T9 name (i.e. 75 -> "Jessica [Jo]nes")
int index = matcher.start();
@@ -79,11 +82,12 @@ public class QueryBoldingUtil {
} else {
// query match the T9 initials (i.e. 222 -> "[A]l [B]ob [C]harlie")
- return getNameWithInitialsBolded(query, name);
+ return getNameWithInitialsBolded(query, name, context);
}
}
- private static CharSequence getNameWithInitialsBolded(String query, String name) {
+ private static CharSequence getNameWithInitialsBolded(
+ String query, String name, Context context) {
SpannableString boldedInitials = new SpannableString(name);
name = name.toLowerCase();
int initialsBolded = 0;
@@ -91,7 +95,8 @@ public class QueryBoldingUtil {
while (++nameIndex < name.length() && initialsBolded < query.length()) {
if ((nameIndex == 0 || name.charAt(nameIndex - 1) == ' ')
- && QueryFilteringUtil.getDigit(name.charAt(nameIndex)) == query.charAt(initialsBolded)) {
+ && QueryFilteringUtil.getDigit(name.charAt(nameIndex), context)
+ == query.charAt(initialsBolded)) {
boldedInitials.setSpan(
new StyleSpan(Typeface.BOLD),
nameIndex,
diff --git a/java/com/android/dialer/searchfragment/common/QueryFilteringUtil.java b/java/com/android/dialer/searchfragment/common/QueryFilteringUtil.java
index 6b5cea88d..1ecb486d2 100644
--- a/java/com/android/dialer/searchfragment/common/QueryFilteringUtil.java
+++ b/java/com/android/dialer/searchfragment/common/QueryFilteringUtil.java
@@ -16,14 +16,24 @@
package com.android.dialer.searchfragment.common;
+import android.content.Context;
import android.support.annotation.NonNull;
+import android.support.v4.util.SimpleArrayMap;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
+import com.android.dialer.dialpadview.DialpadCharMappings;
import java.util.regex.Pattern;
/** Utility class for filtering, comparing and handling strings and queries. */
public class QueryFilteringUtil {
+ /**
+ * The default character-digit map that will be used to find the digit associated with a given
+ * character on a T9 keyboard.
+ */
+ private static final SimpleArrayMap<Character, Character> DEFAULT_CHAR_TO_DIGIT_MAP =
+ DialpadCharMappings.getDefaultCharToKeyMap();
+
/** Matches strings with "-", "(", ")", 2-9 of at least length one. */
private static final Pattern T9_PATTERN = Pattern.compile("[\\-()2-9]+");
@@ -38,15 +48,29 @@ public class QueryFilteringUtil {
* <li>#nameMatchesT9Query("56", "Jessica Jones") returns true, 56 -> 'Jo'
* <li>#nameMatchesT9Query("7", "Jessica Jones") returns false, no names start with P,Q,R or S
* </ul>
+ *
+ * <p>When the 1st language preference uses a non-Latin alphabet (e.g., Russian) and the character
+ * mappings for the alphabet is defined in {@link DialpadCharMappings}, the Latin alphabet will be
+ * used first to check if the name matches the query. If they don't match, the non-Latin alphabet
+ * will be used.
+ *
+ * <p>Examples (when the 1st language preference is Russian):
+ *
+ * <ul>
+ * <li>#nameMatchesT9Query("7", "John Smith") returns true, 7 -> 'S'
+ * <li>#nameMatchesT9Query("7", "Павел Чехов") returns true, 7 -> 'Ч'
+ * <li>#nameMatchesT9Query("77", "Pavel Чехов") returns true, 7 -> 'P' (in the Latin alphabet),
+ * 7 -> 'Ч' (in the Russian alphabet)
+ * </ul>
*/
- public static boolean nameMatchesT9Query(String query, String name) {
+ public static boolean nameMatchesT9Query(String query, String name, Context context) {
if (!T9_PATTERN.matcher(query).matches()) {
return false;
}
query = digitsOnly(query);
Pattern pattern = Pattern.compile("(^|\\s)" + Pattern.quote(query));
- if (pattern.matcher(getT9Representation(name)).find()) {
+ if (pattern.matcher(getT9Representation(name, context)).find()) {
// query matches the start of a T9 name (i.e. 75 -> "Jessica [Jo]nes")
return true;
}
@@ -61,7 +85,7 @@ public class QueryFilteringUtil {
continue;
}
- if (getDigit(names[i].charAt(0)) == query.charAt(queryIndex)) {
+ if (getDigit(names[i].charAt(0), context) == query.charAt(queryIndex)) {
queryIndex++;
}
}
@@ -106,11 +130,17 @@ public class QueryFilteringUtil {
return digitsOnly(number).indexOf(digitsOnly(query));
}
- // Returns string with letters replaced with their T9 representation.
- static String getT9Representation(String s) {
+ /**
+ * Replaces characters in the given string with their T9 representations.
+ *
+ * @param s The original string
+ * @param context The context
+ * @return The original string with characters replaced with T9 representations.
+ */
+ static String getT9Representation(String s, Context context) {
StringBuilder builder = new StringBuilder(s.length());
for (char c : s.toLowerCase().toCharArray()) {
- builder.append(getDigit(c));
+ builder.append(getDigit(c, context));
}
return builder.toString();
}
@@ -127,45 +157,26 @@ public class QueryFilteringUtil {
return sb.toString();
}
- // Returns the T9 representation of a lower case character, otherwise returns the character.
- static char getDigit(char c) {
- switch (c) {
- case 'a':
- case 'b':
- case 'c':
- return '2';
- case 'd':
- case 'e':
- case 'f':
- return '3';
- case 'g':
- case 'h':
- case 'i':
- return '4';
- case 'j':
- case 'k':
- case 'l':
- return '5';
- case 'm':
- case 'n':
- case 'o':
- return '6';
- case 'p':
- case 'q':
- case 'r':
- case 's':
- return '7';
- case 't':
- case 'u':
- case 'v':
- return '8';
- case 'w':
- case 'x':
- case 'y':
- case 'z':
- return '9';
- default:
- return c;
+ /**
+ * Returns the digit on a T9 keyboard which is associated with the given lower case character.
+ *
+ * <p>The default character-key mapping will be used first to find a digit. If no digit is found,
+ * try the mapping of the current default locale if it is defined in {@link DialpadCharMappings}.
+ * If the second attempt fails, return the original character.
+ */
+ static char getDigit(char c, Context context) {
+ Character digit = DEFAULT_CHAR_TO_DIGIT_MAP.get(c);
+ if (digit != null) {
+ return digit;
+ }
+
+ SimpleArrayMap<Character, Character> charToKeyMap =
+ DialpadCharMappings.getCharToKeyMap(context);
+ if (charToKeyMap != null) {
+ digit = charToKeyMap.get(c);
+ return digit != null ? digit : c;
}
+
+ return c;
}
}
diff --git a/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java b/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java
index 84c22a2cf..df67b762f 100644
--- a/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java
+++ b/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java
@@ -17,6 +17,7 @@
package com.android.dialer.searchfragment.cp2;
import android.content.ContentResolver;
+import android.content.Context;
import android.database.CharArrayBuffer;
import android.database.ContentObserver;
import android.database.Cursor;
@@ -44,7 +45,7 @@ import java.util.Set;
* Wrapper for a cursor containing all on device contacts.
*
* <p>This cursor removes duplicate phone numbers associated with the same contact and can filter
- * contacts based on a query by calling {@link #filter(String)}.
+ * contacts based on a query by calling {@link #filter(String, Context)}.
*/
final class ContactFilterCursor implements Cursor {
@@ -72,10 +73,11 @@ final class ContactFilterCursor implements Cursor {
/**
* @param cursor with projection {@link Projections#CP2_PROJECTION}.
* @param query to filter cursor results.
+ * @param context of the app.
*/
- ContactFilterCursor(Cursor cursor, @Nullable String query) {
+ ContactFilterCursor(Cursor cursor, @Nullable String query, Context context) {
this.cursor = createCursor(cursor);
- filter(query);
+ filter(query, context);
}
/**
@@ -238,7 +240,7 @@ final class ContactFilterCursor implements Cursor {
* <li>Its company contains the query
* </ul>
*/
- public void filter(@Nullable String query) {
+ public void filter(@Nullable String query, Context context) {
if (query == null) {
query = "";
}
@@ -253,7 +255,7 @@ final class ContactFilterCursor implements Cursor {
String companyName = cursor.getString(Projections.COMPANY_NAME);
String nickName = cursor.getString(Projections.NICKNAME);
if (TextUtils.isEmpty(query)
- || QueryFilteringUtil.nameMatchesT9Query(query, name)
+ || QueryFilteringUtil.nameMatchesT9Query(query, name, context)
|| QueryFilteringUtil.numberMatchesNumberQuery(query, number)
|| QueryFilteringUtil.nameContainsQuery(query, name)
|| QueryFilteringUtil.nameContainsQuery(query, companyName)
diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
index c09396c72..386ab3a6b 100644
--- a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
+++ b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
@@ -104,7 +104,7 @@ public final class SearchContactViewHolder extends ViewHolder implements OnClick
: context.getString(
com.android.contacts.common.R.string.call_subject_type_and_number, label, number);
- nameOrNumberView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name));
+ nameOrNumberView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name, context));
numberView.setText(QueryBoldingUtil.getNumberWithQueryBolded(query, secondaryInfo));
setCallToAction(cursor, query);
diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java
index 508ca7f57..7697e0520 100644
--- a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java
+++ b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java
@@ -32,17 +32,19 @@ import com.android.dialer.searchfragment.common.SearchCursor;
final class SearchContactsCursor extends MergeCursor implements SearchCursor {
private final ContactFilterCursor contactFilterCursor;
+ private final Context context;
static SearchContactsCursor newInstance(
Context context, ContactFilterCursor contactFilterCursor) {
MatrixCursor headerCursor = new MatrixCursor(HEADER_PROJECTION);
headerCursor.addRow(new String[] {context.getString(R.string.all_contacts)});
- return new SearchContactsCursor(new Cursor[] {headerCursor, contactFilterCursor});
+ return new SearchContactsCursor(new Cursor[] {headerCursor, contactFilterCursor}, context);
}
- private SearchContactsCursor(Cursor[] cursors) {
+ private SearchContactsCursor(Cursor[] cursors, Context context) {
super(cursors);
- contactFilterCursor = (ContactFilterCursor) cursors[1];
+ this.contactFilterCursor = (ContactFilterCursor) cursors[1];
+ this.context = context;
}
@Override
@@ -52,7 +54,7 @@ final class SearchContactsCursor extends MergeCursor implements SearchCursor {
@Override
public boolean updateQuery(@Nullable String query) {
- contactFilterCursor.filter(query);
+ contactFilterCursor.filter(query, context);
return true;
}
diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
index d3abbffca..35518019e 100644
--- a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
+++ b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
@@ -61,7 +61,7 @@ public final class SearchContactsCursorLoader extends CursorLoader {
// All contacts
Cursor cursor = super.loadInBackground();
// Filtering logic
- ContactFilterCursor contactFilterCursor = new ContactFilterCursor(cursor, query);
+ ContactFilterCursor contactFilterCursor = new ContactFilterCursor(cursor, query, getContext());
// Header logic
return SearchContactsCursor.newInstance(getContext(), contactFilterCursor);
}
diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
index 5d5188059..2e1fd5e9d 100644
--- a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
+++ b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
@@ -64,8 +64,8 @@ public final class NearbyPlaceViewHolder extends RecyclerView.ViewHolder
String name = cursor.getString(Projections.DISPLAY_NAME);
String address = cursor.getString(Projections.PHONE_LABEL);
- placeName.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name));
- placeAddress.setText(QueryBoldingUtil.getNameWithQueryBolded(query, address));
+ placeName.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name, context));
+ placeAddress.setText(QueryBoldingUtil.getNameWithQueryBolded(query, address, context));
String photoUri = cursor.getString(Projections.PHOTO_URI);
ContactPhotoManager.getInstance(context)
.loadDialerThumbnailOrPhoto(
diff --git a/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java b/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java
index 8a02eb9b9..339855fbb 100644
--- a/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java
+++ b/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java
@@ -72,8 +72,8 @@ public final class RemoteContactViewHolder extends RecyclerView.ViewHolder
: context.getString(
com.android.contacts.common.R.string.call_subject_type_and_number, label, number);
- nameView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name));
- numberView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, secondaryInfo));
+ nameView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name, context));
+ numberView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, secondaryInfo, context));
if (shouldShowPhoto(cursor)) {
nameView.setVisibility(View.VISIBLE);