Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d5167b4 authored by linyuh's avatar linyuh Committed by Copybara-Service
Browse files

Take into consideration special characters when we do contact match.

Bug: 30225112
Test: CallLogGroupBuilderTest, PhoneNumberHelperTest, CallerInfoTest, and Manual (see demo)
PiperOrigin-RevId: 179080046
Change-Id: I8e451a6c197a6c3df4260e58d0276a5dc5b9515a
parent 35363b34
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -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) {
+11 −0
Original line number Diff line number Diff line
@@ -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);
+88 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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.
+16 −6
Original line number Diff line number Diff line
@@ -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