diff --git a/cpp/src/phonenumbers/phonenumberutil.cc b/cpp/src/phonenumbers/phonenumberutil.cc index 358a9963d..36379aea5 100644 --- a/cpp/src/phonenumbers/phonenumberutil.cc +++ b/cpp/src/phonenumbers/phonenumberutil.cc @@ -386,6 +386,9 @@ class PhoneNumberRegExpsAndMappings { mobile_token_mappings_.insert(std::make_pair(52, '1')); mobile_token_mappings_.insert(std::make_pair(54, '9')); + geo_mobile_countries_.insert(52); // Mexico + geo_mobile_countries_.insert(54); // Argentina + geo_mobile_countries_.insert(55); // Brazil } // Small string helpers since StrCat has a maximum number of arguments. These @@ -445,6 +448,11 @@ class PhoneNumberRegExpsAndMappings { // the length of the mobile token. map mobile_token_mappings_; + // Set of country calling codes that have geographically assigned mobile + // numbers. This may not be complete; we add calling codes case by case, as we + // find geographical mobile numbers or hear from user reports. + set geo_mobile_countries_; + // Pattern that makes it easy to distinguish whether a region has a unique // international dialing prefix or not. If a region has a unique international // prefix (e.g. 011 in USA), it will be represented as a string that contains @@ -530,6 +538,7 @@ class PhoneNumberRegExpsAndMappings { alpha_phone_mappings_(), all_plus_number_grouping_symbols_(), mobile_token_mappings_(), + geo_mobile_countries_(), unique_international_prefix_(regexp_factory_->CreateRegExp( /* "[\\d]+(?:[~⁓∼~][\\d]+)?" */ "[\\d]+(?:[~\xE2\x81\x93\xE2\x88\xBC\xEF\xBD\x9E][\\d]+)?")), @@ -2140,10 +2149,12 @@ bool PhoneNumberUtil::IsValidNumberForRegion(const PhoneNumber& number, bool PhoneNumberUtil::IsNumberGeographical( const PhoneNumber& phone_number) const { PhoneNumberType number_type = GetNumberType(phone_number); - // TODO: Include mobile phone numbers from countries like - // Indonesia, which has some mobile numbers that are geographical. + return number_type == PhoneNumberUtil::FIXED_LINE || - number_type == PhoneNumberUtil::FIXED_LINE_OR_MOBILE; + number_type == PhoneNumberUtil::FIXED_LINE_OR_MOBILE || + (reg_exps_->geo_mobile_countries_.find(phone_number.country_code()) + != reg_exps_->geo_mobile_countries_.end() && + number_type == PhoneNumberUtil::MOBILE); } bool PhoneNumberUtil::IsLeadingZeroPossible(int country_calling_code) const { diff --git a/cpp/test/phonenumbers/phonenumberutil_test.cc b/cpp/test/phonenumbers/phonenumberutil_test.cc index 4f5be02bb..e9cf2b79f 100644 --- a/cpp/test/phonenumbers/phonenumberutil_test.cc +++ b/cpp/test/phonenumbers/phonenumberutil_test.cc @@ -1895,6 +1895,22 @@ TEST_F(PhoneNumberUtilTest, IsNumberGeographical) { number.set_country_code(800); number.set_national_number(12345678ULL); EXPECT_FALSE(IsNumberGeographical(number)); // Internation toll free number. + + // We test that mobile phone numbers in relevant regions are indeed considered + // geographical. + + number.set_country_code(54); + number.set_national_number(91187654321ULL); + EXPECT_TRUE(IsNumberGeographical(number)); // Argentina, mobile phone number. + + number.set_country_code(52); + number.set_national_number(12345678900ULL); + EXPECT_TRUE(IsNumberGeographical(number)); // Mexico, mobile phone number. + + number.set_country_code(52); + number.set_national_number(15512345678ULL); + EXPECT_TRUE(IsNumberGeographical(number)); // Mexico, another mobile phone + // number. } TEST_F(PhoneNumberUtilTest, IsLeadingZeroPossible) { diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java index ae034bd2e..00b0c3480 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java @@ -88,6 +88,11 @@ public class PhoneNumberUtil { // be the length of the area code plus the length of the mobile token. private static final Map MOBILE_TOKEN_MAPPINGS; + // Set of country calling codes that have geographically assigned mobile numbers. This may not be + // complete; we add calling codes case by case, as we find geographical mobile numbers or hear + // from user reports. + private static final Set GEO_MOBILE_COUNTRIES; + // The PLUS_SIGN signifies the international prefix. static final char PLUS_SIGN = '+'; @@ -119,6 +124,12 @@ public class PhoneNumberUtil { mobileTokenMap.put(54, "9"); MOBILE_TOKEN_MAPPINGS = Collections.unmodifiableMap(mobileTokenMap); + HashSet geoMobileCountries = new HashSet(); + geoMobileCountries.add(52); // Mexico + geoMobileCountries.add(54); // Argentina + geoMobileCountries.add(55); // Brazil + GEO_MOBILE_COUNTRIES = Collections.unmodifiableSet(geoMobileCountries); + // Simple ASCII digits map used to populate ALPHA_PHONE_MAPPINGS and // ALL_PLUS_NUMBER_GROUPING_SYMBOLS. HashMap asciiDigitMappings = new HashMap(); @@ -1014,10 +1025,11 @@ public class PhoneNumberUtil { */ boolean isNumberGeographical(PhoneNumber phoneNumber) { PhoneNumberType numberType = getNumberType(phoneNumber); - // TODO: Include mobile phone numbers from countries like Indonesia, which has some - // mobile numbers that are geographical. - return numberType == PhoneNumberType.FIXED_LINE || - numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE; + + return numberType == PhoneNumberType.FIXED_LINE + || numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE + || (GEO_MOBILE_COUNTRIES.contains(phoneNumber.getCountryCode()) + && numberType == PhoneNumberType.MOBILE); } /** diff --git a/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java b/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java index a85eb60a4..8736cb973 100644 --- a/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java +++ b/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java @@ -210,6 +210,10 @@ public class PhoneNumberUtilTest extends TestMetadataTestCase { assertTrue(phoneUtil.isNumberGeographical(AU_NUMBER)); // Australian fixed line number. assertFalse(phoneUtil.isNumberGeographical(INTERNATIONAL_TOLL_FREE)); // International toll // free number. + // We test that mobile phone numbers in relevant regions are indeed considered geographical. + assertTrue(phoneUtil.isNumberGeographical(AR_MOBILE)); // Argentina, mobile phone number. + assertTrue(phoneUtil.isNumberGeographical(MX_MOBILE1)); // Mexico, mobile phone number. + assertTrue(phoneUtil.isNumberGeographical(MX_MOBILE2)); // Mexico, another mobile phone number. } public void testIsLeadingZeroPossible() { diff --git a/java/pending_code_changes.txt b/java/pending_code_changes.txt index d3d23a7a2..bd2056258 100644 --- a/java/pending_code_changes.txt +++ b/java/pending_code_changes.txt @@ -6,3 +6,4 @@ Code changes: - Added getExampleNumberForType that doesn't take in a region, and getInvalidExampleNumber - Improvements to javadoc for parse method + - Update isNumberGeographical to return true for geographical mobile numbers. diff --git a/javascript/i18n/phonenumbers/phonenumberutil.js b/javascript/i18n/phonenumbers/phonenumberutil.js index abceab43e..2b20e4aec 100644 --- a/javascript/i18n/phonenumbers/phonenumberutil.js +++ b/javascript/i18n/phonenumbers/phonenumberutil.js @@ -175,6 +175,22 @@ i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_ = { }; +/** + * Set of country calling codes that have geographically assigned mobile + * numbers. This may not be complete; we add calling codes case by case, as we + * find geographical mobile numbers or hear from user reports. + * + * @const + * @type {!Array.} + * @private + */ +i18n.phonenumbers.PhoneNumberUtil.GEO_MOBILE_COUNTRIES_ = [ + 52, // Mexico + 54, // Argentina + 55 // Brazil +]; + + /** * The PLUS_SIGN signifies the international prefix. * @@ -1371,10 +1387,13 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberGeographical = function(phoneNumber) { /** @type {i18n.phonenumbers.PhoneNumberType} */ var numberType = this.getNumberType(phoneNumber); - // TODO: Include mobile phone numbers from countries like Indonesia, which - // has some mobile numbers that are geographical. + return numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE || - numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE; + numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE || + (goog.array.contains( + i18n.phonenumbers.PhoneNumberUtil.GEO_MOBILE_COUNTRIES_, + phoneNumber.getCountryCodeOrDefault()) && + numberType == i18n.phonenumbers.PhoneNumberType.MOBILE); }; diff --git a/javascript/i18n/phonenumbers/phonenumberutil_test.js b/javascript/i18n/phonenumbers/phonenumberutil_test.js index 8413cbd9a..af37fc581 100644 --- a/javascript/i18n/phonenumbers/phonenumberutil_test.js +++ b/javascript/i18n/phonenumbers/phonenumberutil_test.js @@ -323,6 +323,14 @@ function testIsNumberGeographical() { assertTrue(phoneUtil.isNumberGeographical(AU_NUMBER)); // International toll free number. assertFalse(phoneUtil.isNumberGeographical(INTERNATIONAL_TOLL_FREE)); + // We test that mobile phone numbers in relevant regions are indeed considered + // geographical. + // Argentina, mobile phone number. + assertTrue(phoneUtil.isNumberGeographical(AR_MOBILE)); + // Mexico, mobile phone number. + assertTrue(phoneUtil.isNumberGeographical(MX_MOBILE1)); + // Mexico, another mobile phone number. + assertTrue(phoneUtil.isNumberGeographical(MX_MOBILE2)); } function testIsLeadingZeroPossible() {