Loading java/com/android/dialer/app/calllog/CallLogGroupBuilder.java +15 −2 Original line number Diff line number Diff line Loading @@ -189,13 +189,26 @@ public class CallLogGroupBuilder { mGroupCreator.addGroup(count - groupSize, groupSize); } /** * Returns true when the two input numbers can be considered identical enough for caller ID * purposes and put in a call log group. */ @VisibleForTesting boolean equalNumbers(@Nullable String number1, @Nullable String number2) { if (PhoneNumberHelper.isUriNumber(number1) || PhoneNumberHelper.isUriNumber(number2)) { return compareSipAddresses(number1, number2); } else { return PhoneNumberUtils.compare(number1, number2); } // PhoneNumberUtils.compare(String, String) ignores special characters such as '#'. For example, // it thinks "123" and "#123" are identical enough for caller ID purposes. // When either input number contains special characters, we put the two in the same group iff // their raw numbers are exactly the same. if (PhoneNumberHelper.numberHasSpecialChars(number1) || PhoneNumberHelper.numberHasSpecialChars(number2)) { return PhoneNumberHelper.sameRawNumbers(number1, number2); } return PhoneNumberUtils.compare(number1, number2); } private boolean isSameAccount(String name1, String name2, String id1, String id2) { Loading java/com/android/dialer/phonenumbercache/ContactInfoHelper.java +11 −0 Original line number Diff line number Diff line Loading @@ -355,6 +355,17 @@ public class ContactInfoHelper { return ContactInfo.EMPTY; } // The Contacts provider ignores special characters in phone numbers when searching for a // contact. For example, number "123" is considered a match with a contact with number "#123". // We need to check whether the result contains a number that truly matches the query and move // the cursor to that position before building a ContactInfo. boolean hasNumberMatch = PhoneNumberHelper.updateCursorToMatchContactLookupUri( phoneLookupCursor, PhoneQuery.MATCHED_NUMBER, uri); if (!hasNumberMatch) { return ContactInfo.EMPTY; } String lookupKey = phoneLookupCursor.getString(PhoneQuery.LOOKUP_KEY); ContactInfo contactInfo = createPhoneLookupContactInfo(phoneLookupCursor, lookupKey); fillAdditionalContactInfo(mContext, contactInfo); Loading java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java +88 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.dialer.phonenumberutil; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Trace; import android.provider.CallLog; import android.support.annotation.NonNull; Loading @@ -27,6 +29,7 @@ import android.telephony.TelephonyManager; import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.CompatUtils; import com.android.dialer.compat.telephony.TelephonyManagerCompat; Loading @@ -49,6 +52,91 @@ public class PhoneNumberHelper { && !isLegacyUnknownNumbers(number); } /** * Move the given cursor to a position where the number it points to matches the number in a * contact lookup URI. * * <p>We assume the cursor is one returned by the Contacts Provider when the URI asks for a * specific number. This method's behavior is undefined when the cursor doesn't meet the * assumption. * * <p>When determining whether two phone numbers are identical enough for caller ID purposes, the * Contacts Provider ignores special characters such as '#'. This makes it possible for the cursor * returned by the Contacts Provider to have multiple rows even when the URI asks for a specific * number. * * <p>For example, suppose the user has two contacts whose numbers are "#123" and "123", * respectively. When the URI asks for number "123", both numbers will be returned. Therefore, the * following strategy is employed to find a match. * * <p>In the following description, we use E to denote a number the cursor points to (an existing * contact number), and L to denote the number in the contact lookup URI. * * <p>If neither E nor L contains special characters, return true to indicate a match is found. * * <p>If either E or L contains special characters, return true when the raw numbers of E and L * are the same. Otherwise, move the cursor to its next position and start over. * * <p>Return false in all other circumstances to indicate that no match can be found. * * <p>When no match can be found, the cursor is after the last result when the method returns. * * @param cursor A cursor returned by the Contacts Provider. * @param columnIndexForNumber The index of the column where phone numbers are stored. It is the * caller's responsibility to pass the correct column index. * @param contactLookupUri A URI used to retrieve a contact via the Contacts Provider. It is the * caller's responsibility to ensure the URI is one that asks for a specific phone number. * @return true if a match can be found. */ public static boolean updateCursorToMatchContactLookupUri( @Nullable Cursor cursor, int columnIndexForNumber, @Nullable Uri contactLookupUri) { if (cursor == null || contactLookupUri == null) { return false; } if (!cursor.moveToFirst()) { return false; } Assert.checkArgument( 0 <= columnIndexForNumber && columnIndexForNumber < cursor.getColumnCount()); String lookupNumber = contactLookupUri.getLastPathSegment(); if (TextUtils.isEmpty(lookupNumber)) { return false; } boolean lookupNumberHasSpecialChars = numberHasSpecialChars(lookupNumber); do { String existingContactNumber = cursor.getString(columnIndexForNumber); boolean existingContactNumberHasSpecialChars = numberHasSpecialChars(existingContactNumber); if ((!lookupNumberHasSpecialChars && !existingContactNumberHasSpecialChars) || sameRawNumbers(existingContactNumber, lookupNumber)) { return true; } } while (cursor.moveToNext()); return false; } /** Returns true if the input phone number contains special characters. */ public static boolean numberHasSpecialChars(String number) { return !TextUtils.isEmpty(number) && number.contains("#"); } /** Returns true if the raw numbers of the two input phone numbers are the same. */ public static boolean sameRawNumbers(String number1, String number2) { String rawNumber1 = PhoneNumberUtils.stripSeparators(PhoneNumberUtils.convertKeypadLettersToDigits(number1)); String rawNumber2 = PhoneNumberUtils.stripSeparators(PhoneNumberUtils.convertKeypadLettersToDigits(number2)); return rawNumber1.equals(rawNumber2); } /** * Returns true if the given number is the number of the configured voicemail. To be able to * mock-out this, it is not a static method. Loading java/com/android/incallui/CallerInfo.java +16 −6 Original line number Diff line number Diff line Loading @@ -223,16 +223,26 @@ public class CallerInfo { long contactId = 0L; int columnIndex; // Look for the name columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME); if (columnIndex != -1) { info.name = normalize(cursor.getString(columnIndex)); } // Look for the number columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER); if (columnIndex != -1) { // The Contacts provider ignores special characters in phone numbers when searching for a // contact. For example, number "123" is considered a match with a contact with number "#123". // We need to check whether the result contains a number that truly matches the query and move // the cursor to that position before filling in the fields in CallerInfo. boolean hasNumberMatch = PhoneNumberHelper.updateCursorToMatchContactLookupUri(cursor, columnIndex, contactRef); if (hasNumberMatch) { info.phoneNumber = cursor.getString(columnIndex); } else { return info; } } // Look for the name columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME); if (columnIndex != -1) { info.name = normalize(cursor.getString(columnIndex)); } // Look for the normalized number Loading Loading
java/com/android/dialer/app/calllog/CallLogGroupBuilder.java +15 −2 Original line number Diff line number Diff line Loading @@ -189,13 +189,26 @@ public class CallLogGroupBuilder { mGroupCreator.addGroup(count - groupSize, groupSize); } /** * Returns true when the two input numbers can be considered identical enough for caller ID * purposes and put in a call log group. */ @VisibleForTesting boolean equalNumbers(@Nullable String number1, @Nullable String number2) { if (PhoneNumberHelper.isUriNumber(number1) || PhoneNumberHelper.isUriNumber(number2)) { return compareSipAddresses(number1, number2); } else { return PhoneNumberUtils.compare(number1, number2); } // PhoneNumberUtils.compare(String, String) ignores special characters such as '#'. For example, // it thinks "123" and "#123" are identical enough for caller ID purposes. // When either input number contains special characters, we put the two in the same group iff // their raw numbers are exactly the same. if (PhoneNumberHelper.numberHasSpecialChars(number1) || PhoneNumberHelper.numberHasSpecialChars(number2)) { return PhoneNumberHelper.sameRawNumbers(number1, number2); } return PhoneNumberUtils.compare(number1, number2); } private boolean isSameAccount(String name1, String name2, String id1, String id2) { Loading
java/com/android/dialer/phonenumbercache/ContactInfoHelper.java +11 −0 Original line number Diff line number Diff line Loading @@ -355,6 +355,17 @@ public class ContactInfoHelper { return ContactInfo.EMPTY; } // The Contacts provider ignores special characters in phone numbers when searching for a // contact. For example, number "123" is considered a match with a contact with number "#123". // We need to check whether the result contains a number that truly matches the query and move // the cursor to that position before building a ContactInfo. boolean hasNumberMatch = PhoneNumberHelper.updateCursorToMatchContactLookupUri( phoneLookupCursor, PhoneQuery.MATCHED_NUMBER, uri); if (!hasNumberMatch) { return ContactInfo.EMPTY; } String lookupKey = phoneLookupCursor.getString(PhoneQuery.LOOKUP_KEY); ContactInfo contactInfo = createPhoneLookupContactInfo(phoneLookupCursor, lookupKey); fillAdditionalContactInfo(mContext, contactInfo); Loading
java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java +88 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.dialer.phonenumberutil; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Trace; import android.provider.CallLog; import android.support.annotation.NonNull; Loading @@ -27,6 +29,7 @@ import android.telephony.TelephonyManager; import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.CompatUtils; import com.android.dialer.compat.telephony.TelephonyManagerCompat; Loading @@ -49,6 +52,91 @@ public class PhoneNumberHelper { && !isLegacyUnknownNumbers(number); } /** * Move the given cursor to a position where the number it points to matches the number in a * contact lookup URI. * * <p>We assume the cursor is one returned by the Contacts Provider when the URI asks for a * specific number. This method's behavior is undefined when the cursor doesn't meet the * assumption. * * <p>When determining whether two phone numbers are identical enough for caller ID purposes, the * Contacts Provider ignores special characters such as '#'. This makes it possible for the cursor * returned by the Contacts Provider to have multiple rows even when the URI asks for a specific * number. * * <p>For example, suppose the user has two contacts whose numbers are "#123" and "123", * respectively. When the URI asks for number "123", both numbers will be returned. Therefore, the * following strategy is employed to find a match. * * <p>In the following description, we use E to denote a number the cursor points to (an existing * contact number), and L to denote the number in the contact lookup URI. * * <p>If neither E nor L contains special characters, return true to indicate a match is found. * * <p>If either E or L contains special characters, return true when the raw numbers of E and L * are the same. Otherwise, move the cursor to its next position and start over. * * <p>Return false in all other circumstances to indicate that no match can be found. * * <p>When no match can be found, the cursor is after the last result when the method returns. * * @param cursor A cursor returned by the Contacts Provider. * @param columnIndexForNumber The index of the column where phone numbers are stored. It is the * caller's responsibility to pass the correct column index. * @param contactLookupUri A URI used to retrieve a contact via the Contacts Provider. It is the * caller's responsibility to ensure the URI is one that asks for a specific phone number. * @return true if a match can be found. */ public static boolean updateCursorToMatchContactLookupUri( @Nullable Cursor cursor, int columnIndexForNumber, @Nullable Uri contactLookupUri) { if (cursor == null || contactLookupUri == null) { return false; } if (!cursor.moveToFirst()) { return false; } Assert.checkArgument( 0 <= columnIndexForNumber && columnIndexForNumber < cursor.getColumnCount()); String lookupNumber = contactLookupUri.getLastPathSegment(); if (TextUtils.isEmpty(lookupNumber)) { return false; } boolean lookupNumberHasSpecialChars = numberHasSpecialChars(lookupNumber); do { String existingContactNumber = cursor.getString(columnIndexForNumber); boolean existingContactNumberHasSpecialChars = numberHasSpecialChars(existingContactNumber); if ((!lookupNumberHasSpecialChars && !existingContactNumberHasSpecialChars) || sameRawNumbers(existingContactNumber, lookupNumber)) { return true; } } while (cursor.moveToNext()); return false; } /** Returns true if the input phone number contains special characters. */ public static boolean numberHasSpecialChars(String number) { return !TextUtils.isEmpty(number) && number.contains("#"); } /** Returns true if the raw numbers of the two input phone numbers are the same. */ public static boolean sameRawNumbers(String number1, String number2) { String rawNumber1 = PhoneNumberUtils.stripSeparators(PhoneNumberUtils.convertKeypadLettersToDigits(number1)); String rawNumber2 = PhoneNumberUtils.stripSeparators(PhoneNumberUtils.convertKeypadLettersToDigits(number2)); return rawNumber1.equals(rawNumber2); } /** * Returns true if the given number is the number of the configured voicemail. To be able to * mock-out this, it is not a static method. Loading
java/com/android/incallui/CallerInfo.java +16 −6 Original line number Diff line number Diff line Loading @@ -223,16 +223,26 @@ public class CallerInfo { long contactId = 0L; int columnIndex; // Look for the name columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME); if (columnIndex != -1) { info.name = normalize(cursor.getString(columnIndex)); } // Look for the number columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER); if (columnIndex != -1) { // The Contacts provider ignores special characters in phone numbers when searching for a // contact. For example, number "123" is considered a match with a contact with number "#123". // We need to check whether the result contains a number that truly matches the query and move // the cursor to that position before filling in the fields in CallerInfo. boolean hasNumberMatch = PhoneNumberHelper.updateCursorToMatchContactLookupUri(cursor, columnIndex, contactRef); if (hasNumberMatch) { info.phoneNumber = cursor.getString(columnIndex); } else { return info; } } // Look for the name columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME); if (columnIndex != -1) { info.name = normalize(cursor.getString(columnIndex)); } // Look for the normalized number Loading