From 006d071bd477768b4685385d15b3385f6d2e834d Mon Sep 17 00:00:00 2001 From: Yorke Lee Date: Tue, 30 Apr 2013 17:49:03 -0700 Subject: Apply NANP logic to numbers with a +1 country code Bug 8769688 Change-Id: I4aadd0f9e5495fb1b604910306dfd918d1540136 --- .../dialer/dialpad/SmartDialNameMatcher.java | 25 ++++++++-- src/com/android/dialer/dialpad/SmartDialTrie.java | 57 +++++++++++++--------- .../dialer/dialpad/SmartDialNameMatcherTest.java | 11 +++++ .../android/dialer/dialpad/SmartDialTrieTest.java | 24 ++++++++- 4 files changed, 89 insertions(+), 28 deletions(-) diff --git a/src/com/android/dialer/dialpad/SmartDialNameMatcher.java b/src/com/android/dialer/dialpad/SmartDialNameMatcher.java index f8877c665..f7ae1c232 100644 --- a/src/com/android/dialer/dialpad/SmartDialNameMatcher.java +++ b/src/com/android/dialer/dialpad/SmartDialNameMatcher.java @@ -18,6 +18,8 @@ package com.android.dialer.dialpad; import android.text.TextUtils; +import com.android.dialer.dialpad.SmartDialTrie.CountryCodeWithOffset; + import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; @@ -426,8 +428,19 @@ public class SmartDialNameMatcher { * @return Phone number consisting of digits from 0-9 */ public static String normalizeNumber(String number) { + return normalizeNumber(number, 0); + } + + /** + * Strips a phone number of unnecessary characters (spaces, dashes, etc.) + * + * @param number Phone number we want to normalize + * @param offset Offset to start from + * @return Phone number consisting of digits from 0-9 + */ + public static String normalizeNumber(String number, int offset) { final StringBuilder s = new StringBuilder(); - for (int i = 0; i < number.length(); i++) { + for (int i = offset; i < number.length(); i++) { char ch = number.charAt(i); if (ch >= '0' && ch <= '9') { s.append(ch); @@ -452,10 +465,12 @@ public class SmartDialNameMatcher { SmartDialMatchPosition matchPos = matchesNumberWithOffset(phoneNumber, query, 0); if (matchPos == null) { // Try matching the number without the '+' prefix, if any - int offset = SmartDialTrie.getOffsetWithoutCountryCode(phoneNumber); - if (offset > 0) { - matchPos = matchesNumberWithOffset(phoneNumber, query, offset); - } else if (matchNanp) { + final CountryCodeWithOffset code = SmartDialTrie.getOffsetWithoutCountryCode( + phoneNumber); + if (code != null) { + matchPos = matchesNumberWithOffset(phoneNumber, query, code.offset); + } + if (matchPos == null && matchNanp) { // Try matching NANP numbers final int[] offsets = SmartDialTrie.getOffsetForNANPNumbers(phoneNumber); for (int i = 0; i < offsets.length; i++) { diff --git a/src/com/android/dialer/dialpad/SmartDialTrie.java b/src/com/android/dialer/dialpad/SmartDialTrie.java index 04ff64c5b..ab935b73a 100644 --- a/src/com/android/dialer/dialpad/SmartDialTrie.java +++ b/src/com/android/dialer/dialpad/SmartDialTrie.java @@ -45,13 +45,33 @@ public class SmartDialTrie { int nthLastTokenPos; } - private static final int LAST_TOKENS_FOR_INITIALS = 2; - private static final int FIRST_TOKENS_FOR_INITIALS = 2; + /** + * A country code and integer offset pair that represents the parsed country code in a + * phone number. The country code is a string containing the numeric country-code prefix in + * a phone number (e.g. 1 or 852). The offset is the integer position of where the country code + * ends in a phone number. + */ + public static class CountryCodeWithOffset { + public static final CountryCodeWithOffset NO_COUNTRY_CODE = new CountryCodeWithOffset(0, + ""); + + final String countryCode; + final int offset; + + public CountryCodeWithOffset(int offset, String countryCode) { + this.countryCode = countryCode; + this.offset = offset; + } + } + final Node mRoot = new Node(); private int mSize = 0; private final char[] mCharacterMap; private final boolean mFormatNanp; + private static final int LAST_TOKENS_FOR_INITIALS = 2; + private static final int FIRST_TOKENS_FOR_INITIALS = 2; + // Static set of all possible country codes in the world public static Set sCountryCodes = null; @@ -134,12 +154,14 @@ public class SmartDialTrie { // Strip the calling code from the phone number here if (!TextUtils.isEmpty(contact.phoneNumber)) { // Handle country codes for numbers with a + prefix - final int offset = getOffsetWithoutCountryCode(contact.phoneNumber); - if (offset > 0) { - putNumber(contact, contact.phoneNumber, offset); - } else if (mFormatNanp) { + final CountryCodeWithOffset code = getOffsetWithoutCountryCode(contact.phoneNumber); + if (code.offset != 0) { + putNumber(contact, contact.phoneNumber, code.offset); + } + if ((code.countryCode.equals("1") || code.offset == 0) && mFormatNanp) { // Special case handling for NANP numbers (1-xxx-xxx-xxxx) - final String stripped = SmartDialNameMatcher.normalizeNumber(contact.phoneNumber); + final String stripped = SmartDialNameMatcher.normalizeNumber( + contact.phoneNumber, code.offset); if (!TextUtils.isEmpty(stripped)) { int trunkPrefixOffset = 0; if (stripped.charAt(0) == '1') { @@ -159,24 +181,25 @@ public class SmartDialTrie { } } } - putNumber(contact, contact.phoneNumber); + putNumber(contact, contact.phoneNumber, 0); } mSize++; } - public static int getOffsetWithoutCountryCode(String number) { + public static CountryCodeWithOffset getOffsetWithoutCountryCode(String number) { if (!TextUtils.isEmpty(number)) { if (number.charAt(0) == '+') { // check for international code here for (int i = 1; i <= 1 + 3; i++) { if (number.length() <= i) break; - if (isValidCountryCode(number.substring(1, i))) { - return i; + final String countryCode = number.substring(1, i); + if (isValidCountryCode(countryCode)) { + return new CountryCodeWithOffset(i, countryCode); } } } } - return -1; + return CountryCodeWithOffset.NO_COUNTRY_CODE; } /** @@ -273,16 +296,6 @@ public class SmartDialTrie { return info; } - /** - * Puts a phone number and its associated contact into the prefix trie. - * - * @param contact - Contact to add to the trie - * @param phoneNumber - Phone number of the contact - */ - private void putNumber(ContactNumber contact, String phoneNumber) { - putNumber(contact, phoneNumber, 0); - } - /** * Puts a phone number and its associated contact into the prefix trie. * diff --git a/tests/src/com/android/dialer/dialpad/SmartDialNameMatcherTest.java b/tests/src/com/android/dialer/dialpad/SmartDialNameMatcherTest.java index 83b856059..eb6f05087 100644 --- a/tests/src/com/android/dialer/dialpad/SmartDialNameMatcherTest.java +++ b/tests/src/com/android/dialer/dialpad/SmartDialNameMatcherTest.java @@ -201,6 +201,17 @@ public class SmartDialNameMatcherTest extends TestCase { checkMatchesNumber("1-510-333-7596", "5103337596", true, true, 2, 14); checkMatchesNumber("1-510-333-7596", "3337596", true, true, 6, 14); + // An 11 digit number prefixed with +1 should be matched by the 10 digit number, as well as + // the 7 digit number (without area code) + checkMatchesNumber("+1-510-333-7596", "5103337596", true, true, 3, 15); + checkMatchesNumber("+1-510-333-7596", "3337596", true, true, 7, 15); + checkMatchesNumber("+1-510-333-7596", "103337596", false, true, 0, 0); + checkMatchesNumber("+1-510-333-7596", "337596", false, true, 0, 0); + checkMatchesNumber("+1510 3337596", "5103337596", true, true, 2, 13); + checkMatchesNumber("+1510 3337596", "3337596", true, true, 6, 13); + checkMatchesNumber("+1510 3337596", "103337596", false, true, 0, 0); + checkMatchesNumber("+1510 3337596", "37596", false, true, 0, 0); + // Invalid NANP numbers should not be matched checkMatchesNumber("1-510-333-759", "510333759", false, true, 0, 0); checkMatchesNumber("510-333-759", "333759", false, true, 0, 0); diff --git a/tests/src/com/android/dialer/dialpad/SmartDialTrieTest.java b/tests/src/com/android/dialer/dialpad/SmartDialTrieTest.java index 876e00de7..f0c4cbb46 100644 --- a/tests/src/com/android/dialer/dialpad/SmartDialTrieTest.java +++ b/tests/src/com/android/dialer/dialpad/SmartDialTrieTest.java @@ -294,7 +294,6 @@ public class SmartDialTrieTest extends TestCase{ // Tests special case handling for NANP numbers public void testPutNumbersNANP() { - final SmartDialTrie trie = new SmartDialTrie(true /* formatNanp */); // Unformatted number with 1 prefix final ContactNumber contactno1 = new ContactNumber(0, "James", "16503337596", "0", 1); @@ -340,6 +339,29 @@ public class SmartDialTrieTest extends TestCase{ // But the NANP special case handling should not work assertFalse(checkContains(trie, contactno6, "123123")); + // Number with +1 prefix and is a NANP number + final ContactNumber contactno7 = new ContactNumber(0, "Mike", "+1-510-284-9170", "0", 1); + trie.put(contactno7); + assertTrue(checkContains(trie, contactno7, "15102849170")); + assertTrue(checkContains(trie, contactno7, "5102849170")); + assertTrue(checkContains(trie, contactno7, "2849170")); + assertFalse(checkContains(trie, contactno7, "849170")); + assertFalse(checkContains(trie, contactno7, "10849170")); + + // Number with +1 prefix but is an invalid NANP number + final ContactNumber contactno8 = new ContactNumber(0, "Invalid", "+1-510-284-917", "0", 1); + trie.put(contactno8); + assertTrue(checkContains(trie, contactno8, "1510284917")); + assertTrue(checkContains(trie, contactno8, "510284917")); + assertFalse(checkContains(trie, contactno8, "2849170")); + + // Number with invalid country code prefix + final ContactNumber contactno9 = new ContactNumber(0, "Inv", "+857-510-284-9170", "0", 1); + trie.put(contactno9); + assertTrue(checkContains(trie, contactno9, "8575102849170")); + assertFalse(checkContains(trie, contactno9, "5102849170")); + assertFalse(checkContains(trie, contactno9, "2849170")); + // If user's region is determined to be not in North America, then the NANP number // workarounds should not be applied final SmartDialTrie trieNonNANP = new SmartDialTrie(); -- cgit v1.2.3