CPP: Add number formatting for mobile dialling
authorphilip.liard@gmail.com <philip.liard@gmail.com@ee073f10-1060-11df-b6a4-87a95322a99c>
Wed, 12 Oct 2011 11:47:24 +0000 (11:47 +0000)
committerphilip.liard@gmail.com <philip.liard@gmail.com@ee073f10-1060-11df-b6a4-87a95322a99c>
Wed, 12 Oct 2011 11:47:24 +0000 (11:47 +0000)
git-svn-id: http://libphonenumber.googlecode.com/svn/trunk@367 ee073f10-1060-11df-b6a4-87a95322a99c

cpp/src/phonenumbers/phonenumberutil.cc
cpp/src/phonenumbers/phonenumberutil.h
cpp/test/phonenumbers/phonenumberutil_test.cc

index d1faafb..4d5fe73 100644 (file)
@@ -99,6 +99,10 @@ scoped_ptr<map<char32, char> > alpha_phone_mappings;
 // as "-" and " ".
 scoped_ptr<map<char32, char> > all_plus_number_grouping_symbols;
 
+// The prefix that needs to be inserted in front of a Colombian landline
+// number when dialed from a mobile phone in Colombia.
+const char kColombiaMobileToFixedLinePrefix[] = "3";
+
 // The kPlusSign signifies the international prefix.
 const char kPlusSign[] = "+";
 
@@ -987,6 +991,56 @@ void PhoneNumberUtil::FormatNationalNumberWithPreferredCarrierCode(
       formatted_number);
 }
 
+void PhoneNumberUtil::FormatNumberForMobileDialing(
+    const PhoneNumber& number,
+    const string& calling_from,
+    bool with_formatting,
+    string* formatted_number) const {
+  string region_code;
+  GetRegionCodeForNumber(number, &region_code);
+  if (!IsValidRegionCode(region_code)) {
+    formatted_number->assign(number.has_raw_input() ? number.raw_input() : "");
+    return;
+  }
+
+  // Clear the extension, as that part cannot normally be dialed together with
+  // the main number.
+  PhoneNumber number_no_extension(number);
+  number_no_extension.clear_extension();
+  PhoneNumberType number_type = GetNumberType(number_no_extension);
+  if ((region_code == "CO") && (calling_from == "CO") &&
+      (number_type == FIXED_LINE)) {
+      FormatNationalNumberWithCarrierCode(
+          number_no_extension, kColombiaMobileToFixedLinePrefix,
+          formatted_number);
+  } else if ((region_code == "BR") && (calling_from == "BR") &&
+      ((number_type == FIXED_LINE) || (number_type == MOBILE) ||
+       (number_type == FIXED_LINE_OR_MOBILE))) {
+    if (number_no_extension.has_preferred_domestic_carrier_code()) {
+      FormatNationalNumberWithPreferredCarrierCode(number_no_extension, "",
+                                                   formatted_number);
+    } else {
+      // Brazilian fixed line and mobile numbers need to be dialed with a
+      // carrier code when called within Brazil. Without that, most of the
+      // carriers won't connect the call. Because of that, we return an empty
+      // string here.
+      formatted_number->assign("");
+    }
+  } else if (CanBeInternationallyDialled(number_no_extension)) {
+    with_formatting
+        ? Format(number_no_extension, INTERNATIONAL, formatted_number)
+        : Format(number_no_extension, E164, formatted_number);
+    return;
+  } else if (calling_from == region_code) {
+    Format(number_no_extension, NATIONAL, formatted_number);
+  } else {
+    formatted_number->assign("");
+  }
+  if (!with_formatting) {
+    NormalizeDigitsOnly(formatted_number);
+  }
+}
+
 void PhoneNumberUtil::FormatOutOfCountryCallingNumber(
     const PhoneNumber& number,
     const string& calling_from,
@@ -2257,5 +2311,20 @@ AsYouTypeFormatter* PhoneNumberUtil::GetAsYouTypeFormatter(
   return new AsYouTypeFormatter(region_code);
 }
 
+bool PhoneNumberUtil::CanBeInternationallyDialled(
+    const PhoneNumber& number) const {
+  string region_code;
+  GetRegionCodeForNumber(number, &region_code);
+  string national_significant_number;
+  GetNationalSignificantNumber(number, &national_significant_number);
+  if (!HasValidRegionCode(region_code, number.country_code(),
+                          national_significant_number)) {
+    return true;
+  }
+  const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
+  return !IsNumberMatchingDesc(
+      national_significant_number, metadata->no_international_dialling());
+}
+
 }  // namespace phonenumbers
 }  // namespace i18n
index 6bc8022..f2979c4 100644 (file)
@@ -298,6 +298,16 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
       const string& fallback_carrier_code,
       string* formatted_number) const;
 
+  // Returns a number formatted in such a way that it can be dialed from a
+  // mobile phone in a specific region. If the number cannot be reached from
+  // the region (e.g. some countries block toll-free numbers from being called
+  // outside of the country), the method returns an empty string.
+  void FormatNumberForMobileDialing(
+      const PhoneNumber& number,
+      const string& region_calling_from,
+      bool with_formatting,
+      string* formatted_number) const;
+
   // Formats a phone number for out-of-country dialing purposes.
   //
   // Note this function takes care of the case for calling inside of NANPA
@@ -675,6 +685,11 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
                         bool check_region,
                         PhoneNumber* phone_number) const;
 
+  // Returns true if the number can only be dialled from within the region. If
+  // unknown, or the number can be dialled from outside the region as well,
+  // returns false. Does not check the number is a valid number.
+  bool CanBeInternationallyDialled(const PhoneNumber& number) const;
+
   DISALLOW_COPY_AND_ASSIGN(PhoneNumberUtil);
 };
 
index f350350..9a0cca5 100644 (file)
@@ -56,6 +56,10 @@ class PhoneNumberUtilTest : public testing::Test {
     phone_util_.ExtractPossibleNumber(number, extracted_number);
   }
 
+  bool CanBeInternationallyDialled(const PhoneNumber& number) const {
+    return phone_util_.CanBeInternationallyDialled(number);
+  }
+
   bool IsViablePhoneNumber(const string& number) const {
     return phone_util_.IsViablePhoneNumber(number);
   }
@@ -787,6 +791,44 @@ TEST_F(PhoneNumberUtilTest, FormatWithPreferredCarrierCode) {
   EXPECT_EQ("424 123 1234", formatted_number);
 }
 
+TEST_F(PhoneNumberUtilTest, FormatNumberForMobileDialing) {
+  PhoneNumber test_number;
+  string formatted_number;
+  test_number.set_country_code(1);
+
+  // US toll free numbers are marked as noInternationalDialling in the test
+  // metadata for testing purposes.
+  test_number.set_national_number(8002530000ULL);
+  phone_util_.FormatNumberForMobileDialing(
+      test_number, RegionCode::US(), true, &formatted_number);
+  EXPECT_EQ("800 253 0000", formatted_number);
+  phone_util_.FormatNumberForMobileDialing(
+      test_number, RegionCode::CN(), true, &formatted_number);
+  EXPECT_EQ("", formatted_number);
+  phone_util_.FormatNumberForMobileDialing(
+      test_number, RegionCode::US(), false, &formatted_number);
+  EXPECT_EQ("8002530000", formatted_number);
+  phone_util_.FormatNumberForMobileDialing(
+      test_number, RegionCode::CN(), false, &formatted_number);
+  EXPECT_EQ("", formatted_number);
+
+  test_number.set_national_number(6502530000ULL);
+  phone_util_.FormatNumberForMobileDialing(
+      test_number, RegionCode::US(), true, &formatted_number);
+  EXPECT_EQ("+1 650 253 0000", formatted_number);
+  phone_util_.FormatNumberForMobileDialing(
+      test_number, RegionCode::US(), false, &formatted_number);
+  EXPECT_EQ("+16502530000", formatted_number);
+
+  test_number.set_extension("1234");
+  phone_util_.FormatNumberForMobileDialing(
+      test_number, RegionCode::US(), true, &formatted_number);
+  EXPECT_EQ("+1 650 253 0000", formatted_number);
+  phone_util_.FormatNumberForMobileDialing(
+      test_number, RegionCode::US(), false, &formatted_number);
+  EXPECT_EQ("+16502530000", formatted_number);
+}
+
 TEST_F(PhoneNumberUtilTest, FormatByPattern) {
   PhoneNumber test_number;
   string formatted_number;
@@ -2827,6 +2869,29 @@ TEST_F(PhoneNumberUtilTest, ParseAndKeepRaw) {
   EXPECT_EQ(korean_number, test_number);
 }
 
+TEST_F(PhoneNumberUtilTest, CanBeInternationallyDialled) {
+  PhoneNumber test_number;
+  test_number.set_country_code(1);
+
+  // We have no-international-dialling rules for the US in our test metadata
+  // that say that toll-free numbers cannot be dialled internationally.
+  test_number.set_national_number(8002530000ULL);
+  EXPECT_FALSE(CanBeInternationallyDialled(test_number));
+
+  // Normal US numbers can be internationally dialled.
+  test_number.set_national_number(6502530000ULL);
+  EXPECT_TRUE(CanBeInternationallyDialled(test_number));
+
+  // Invalid number.
+  test_number.set_national_number(2530000ULL);
+  EXPECT_TRUE(CanBeInternationallyDialled(test_number));
+
+  // We have no data for NZ - should return true.
+  test_number.set_country_code(64);
+  test_number.set_national_number(33316005ULL);
+  EXPECT_TRUE(CanBeInternationallyDialled(test_number));
+}
+
 TEST_F(PhoneNumberUtilTest, IsAlphaNumber) {
   static const string kAlphaNumber("1800 six-flags");
   EXPECT_TRUE(phone_util_.IsAlphaNumber(kAlphaNumber));