phonelib 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/data/extended_data.dat +0 -0
  3. data/data/libphonenumber/README.md +1 -1
  4. data/data/libphonenumber/cpp/CMakeLists.txt +1 -1
  5. data/data/libphonenumber/cpp/src/phonenumbers/geocoding/phonenumber_offline_geocoder.cc +12 -2
  6. data/data/libphonenumber/cpp/src/phonenumbers/lite_metadata.cc +7951 -7937
  7. data/data/libphonenumber/cpp/src/phonenumbers/metadata.cc +8658 -8642
  8. data/data/libphonenumber/cpp/src/phonenumbers/phonenumberutil.cc +30 -3
  9. data/data/libphonenumber/cpp/src/phonenumbers/phonenumberutil.h +14 -5
  10. data/data/libphonenumber/cpp/src/phonenumbers/short_metadata.cc +1526 -1523
  11. data/data/libphonenumber/cpp/src/phonenumbers/test_metadata.cc +604 -590
  12. data/data/libphonenumber/cpp/test/phonenumbers/geocoding/phonenumber_offline_geocoder_test.cc +9 -0
  13. data/data/libphonenumber/cpp/test/phonenumbers/phonenumberutil_test.cc +24 -5
  14. data/data/libphonenumber/java/build.xml +0 -30
  15. data/data/libphonenumber/java/carrier/pom.xml +4 -4
  16. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/212_en +0 -0
  17. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/251_en +0 -0
  18. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/382_en +0 -0
  19. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/421_en +0 -0
  20. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/852_zh +0 -0
  21. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/852_zh_Hant +0 -0
  22. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/86_en +0 -0
  23. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/86_zh +0 -0
  24. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/86_zh_Hant +0 -0
  25. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/91_en +0 -0
  26. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/963_en +0 -0
  27. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/config +0 -0
  28. data/data/libphonenumber/java/demo/pom.xml +5 -5
  29. data/data/libphonenumber/java/geocoder/pom.xml +4 -4
  30. data/data/libphonenumber/java/geocoder/src/com/google/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder.java +2 -13
  31. data/data/libphonenumber/java/geocoder/src/com/google/i18n/phonenumbers/geocoding/data/212_en +0 -0
  32. data/data/libphonenumber/java/geocoder/test/com/google/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoderTest.java +7 -0
  33. data/data/libphonenumber/java/geocoder/test/com/google/i18n/phonenumbers/geocoding/testing_data/82_en +0 -0
  34. data/data/libphonenumber/java/internal/prefixmapper/pom.xml +3 -3
  35. data/data/libphonenumber/java/lib/protobuf-javanano-3.0.0-alpha-7.jar +0 -0
  36. data/data/libphonenumber/java/lib/protobuf-javanano-readme.md +20 -0
  37. data/data/libphonenumber/java/libphonenumber/pom.xml +6 -43
  38. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/MetadataManager.java +66 -41
  39. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/MultiFileMetadataSourceImpl.java +9 -32
  40. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java +40 -11
  41. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/SingleFileMetadataSourceImpl.java +19 -51
  42. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CO +0 -0
  43. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_EH +0 -0
  44. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_ET +0 -0
  45. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_IN +0 -0
  46. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_JM +0 -0
  47. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MA +0 -0
  48. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_ME +0 -0
  49. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SK +0 -0
  50. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SN +0 -0
  51. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SY +0 -0
  52. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_ZM +0 -0
  53. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/ShortNumberMetadataProto_IN +0 -0
  54. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/ShortNumberMetadataProto_ZA +0 -0
  55. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java +14 -1
  56. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProtoForTesting_CN +0 -0
  57. data/data/libphonenumber/java/pom.xml +1 -1
  58. data/data/libphonenumber/java/release_notes.txt +25 -0
  59. data/data/libphonenumber/javascript/i18n/phonenumbers/demo-compiled.js +88 -88
  60. data/data/libphonenumber/javascript/i18n/phonenumbers/metadata.js +21 -19
  61. data/data/libphonenumber/javascript/i18n/phonenumbers/metadatafortesting.js +7 -5
  62. data/data/libphonenumber/javascript/i18n/phonenumbers/metadatalite.js +21 -19
  63. data/data/libphonenumber/resources/PhoneNumberMetadata.xml +86 -48
  64. data/data/libphonenumber/resources/PhoneNumberMetadataForTesting.xml +33 -2
  65. data/data/libphonenumber/resources/ShortNumberMetadata.xml +24 -8
  66. data/data/libphonenumber/resources/carrier/en/212.txt +16 -3
  67. data/data/libphonenumber/resources/carrier/en/251.txt +1 -0
  68. data/data/libphonenumber/resources/carrier/en/382.txt +29 -0
  69. data/data/libphonenumber/resources/carrier/en/421.txt +1 -0
  70. data/data/libphonenumber/resources/carrier/en/86.txt +13 -1
  71. data/data/libphonenumber/resources/carrier/en/91.txt +1 -0
  72. data/data/libphonenumber/resources/carrier/en/963.txt +50 -0
  73. data/data/libphonenumber/resources/carrier/zh/852.txt +283 -0
  74. data/data/libphonenumber/resources/carrier/zh/86.txt +64 -0
  75. data/data/libphonenumber/resources/carrier/zh_Hant/852.txt +283 -0
  76. data/data/libphonenumber/resources/carrier/zh_Hant/86.txt +64 -0
  77. data/data/libphonenumber/resources/geocoding/en/212.txt +1 -1
  78. data/data/libphonenumber/resources/test/geocoding/en/82.txt +1 -0
  79. data/data/libphonenumber/tools/java/common/pom.xml +4 -9
  80. data/data/libphonenumber/tools/java/cpp-build/pom.xml +4 -31
  81. data/data/libphonenumber/tools/java/cpp-build/target/cpp-build-1.0-SNAPSHOT-jar-with-dependencies.jar +0 -0
  82. data/data/libphonenumber/tools/java/java-build/pom.xml +4 -9
  83. data/data/libphonenumber/tools/java/java-build/target/java-build-1.0-SNAPSHOT-jar-with-dependencies.jar +0 -0
  84. data/data/phone_data.dat +0 -0
  85. data/lib/phonelib/phone.rb +1 -1
  86. data/lib/phonelib/version.rb +1 -1
  87. metadata +18 -8
  88. data/data/libphonenumber/java/lib/com/google/protobuf/protobuf-java/2.6.1/protobuf-java-2.6.1.jar +0 -0
  89. data/data/libphonenumber/java/lib/com/google/protobuf/protobuf-java/2.6.1/protobuf-java-2.6.1.pom +0 -9
  90. data/data/libphonenumber/java/lib/com/google/protobuf/protobuf-java/maven-metadata-local.xml +0 -12
  91. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/SingleFilePhoneNumberMetadataProto +0 -0
  92. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/data/SingleFilePhoneNumberMetadataProtoForTesting +0 -0
@@ -36,13 +36,13 @@ import java.util.logging.Logger;
36
36
  * additional data files such as PhoneNumberAlternateFormats, but in the future it is envisaged it
37
37
  * would handle the main metadata file (PhoneNumberMetadata.xml) as well.
38
38
  */
39
- class MetadataManager {
39
+ final class MetadataManager {
40
40
  private static final String ALTERNATE_FORMATS_FILE_PREFIX =
41
41
  "/com/google/i18n/phonenumbers/data/PhoneNumberAlternateFormatsProto";
42
42
  private static final String SHORT_NUMBER_METADATA_FILE_PREFIX =
43
43
  "/com/google/i18n/phonenumbers/data/ShortNumberMetadataProto";
44
44
 
45
- private static final Logger LOGGER = Logger.getLogger(MetadataManager.class.getName());
45
+ private static final Logger logger = Logger.getLogger(MetadataManager.class.getName());
46
46
 
47
47
  private static final Map<Integer, PhoneMetadata> callingCodeToAlternateFormatsMap =
48
48
  Collections.synchronizedMap(new HashMap<Integer, PhoneMetadata>());
@@ -61,19 +61,15 @@ class MetadataManager {
61
61
  private MetadataManager() {
62
62
  }
63
63
 
64
- private static void close(InputStream in) {
65
- if (in != null) {
66
- try {
67
- in.close();
68
- } catch (IOException e) {
69
- LOGGER.log(Level.WARNING, e.toString());
70
- }
71
- }
72
- }
64
+ // The size of the byte buffer in bytes used to convert a stream containing metadata for a single
65
+ // region, to a nanoproto-compatible CodedInputByteBufferNano. This was determined by the size of
66
+ // the binary metadata files that contain each region's metadata.
67
+ static final int DEFAULT_BUFFER_SIZE = 16 * 1024;
73
68
 
74
- // The size of the byte buffer used for deserializing the alternate formats and short number
75
- // metadata files for each region.
76
- private static final int BUFFER_SIZE = 16 * 1024;
69
+ // The size of the byte buffer in bytes used to convert a stream containing metadata for all
70
+ // regions, to a nanoproto-compatible CodedInputByteBufferNano. This was determined by the size of
71
+ // the binary metadata file that contains all regions' metadata.
72
+ static final int ALL_REGIONS_BUFFER_SIZE = 256 * 1024;
77
73
 
78
74
  static CodedInputByteBufferNano convertStreamToByteBuffer(ObjectInputStream in, int bufferSize)
79
75
  throws IOException {
@@ -89,22 +85,55 @@ class MetadataManager {
89
85
  return CodedInputByteBufferNano.newInstance(outputStream.toByteArray());
90
86
  }
91
87
 
92
- private static void loadAlternateFormatsMetadataFromFile(int countryCallingCode) {
93
- InputStream source = PhoneNumberMatcher.class.getResourceAsStream(
94
- ALTERNATE_FORMATS_FILE_PREFIX + "_" + countryCallingCode);
95
- ObjectInputStream in = null;
88
+ /**
89
+ * Loads and returns the metadata protocol buffer from the given stream and closes the stream.
90
+ *
91
+ * @param source the non-null stream from which metadata is to be read.
92
+ * @param bufferSize the size of the buffer in bytes used to convert the stream to a
93
+ nanoproto-compatible {@code CodedInputByteBufferNano}.
94
+ * @return the loaded metadata protocol buffer.
95
+ */
96
+ static PhoneMetadataCollection loadMetadataAndCloseInput(InputStream source, int bufferSize) {
97
+ ObjectInputStream ois = null;
96
98
  try {
97
- in = new ObjectInputStream(source);
98
- CodedInputByteBufferNano byteBuffer = convertStreamToByteBuffer(in, BUFFER_SIZE);
99
- PhoneMetadataCollection alternateFormats = new PhoneMetadataCollection();
100
- alternateFormats.mergeFrom(byteBuffer);
101
- for (PhoneMetadata metadata : alternateFormats.metadata) {
102
- callingCodeToAlternateFormatsMap.put(metadata.countryCode, metadata);
99
+ try {
100
+ ois = new ObjectInputStream(source);
101
+ } catch (IOException e) {
102
+ throw new RuntimeException("cannot load/parse metadata", e);
103
+ }
104
+ PhoneMetadataCollection metadataCollection = new PhoneMetadataCollection();
105
+ try {
106
+ metadataCollection.mergeFrom(convertStreamToByteBuffer(ois, bufferSize));
107
+ } catch (IOException e) {
108
+ throw new RuntimeException("cannot load/parse metadata", e);
103
109
  }
104
- } catch (IOException e) {
105
- LOGGER.log(Level.WARNING, e.toString());
110
+ return metadataCollection;
106
111
  } finally {
107
- close(in);
112
+ try {
113
+ if (ois != null) {
114
+ // This will close all underlying streams as well, including source.
115
+ ois.close();
116
+ } else {
117
+ source.close();
118
+ }
119
+ } catch (IOException e) {
120
+ logger.log(Level.WARNING, "error closing input stream (ignored)", e);
121
+ }
122
+ }
123
+ }
124
+
125
+ private static void loadAlternateFormatsMetadataFromFile(int countryCallingCode) {
126
+ String fileName = ALTERNATE_FORMATS_FILE_PREFIX + "_" + countryCallingCode;
127
+ InputStream source = MetadataManager.class.getResourceAsStream(fileName);
128
+ if (source == null) {
129
+ // Sanity check; this should not happen since we only load things based on the expectation
130
+ // that they are present, by checking the map of available data first.
131
+ throw new IllegalStateException("missing metadata: " + fileName);
132
+ }
133
+ PhoneMetadataCollection alternateFormatData =
134
+ loadMetadataAndCloseInput(source, DEFAULT_BUFFER_SIZE);
135
+ for (PhoneMetadata metadata : alternateFormatData.metadata) {
136
+ callingCodeToAlternateFormatsMap.put(metadata.countryCode, metadata);
108
137
  }
109
138
  }
110
139
 
@@ -121,21 +150,17 @@ class MetadataManager {
121
150
  }
122
151
 
123
152
  private static void loadShortNumberMetadataFromFile(String regionCode) {
124
- InputStream source = PhoneNumberMatcher.class.getResourceAsStream(
125
- SHORT_NUMBER_METADATA_FILE_PREFIX + "_" + regionCode);
126
- ObjectInputStream in = null;
127
- try {
128
- in = new ObjectInputStream(source);
129
- CodedInputByteBufferNano byteBuffer = convertStreamToByteBuffer(in, BUFFER_SIZE);
130
- PhoneMetadataCollection shortNumberMetadata = new PhoneMetadataCollection();
131
- shortNumberMetadata.mergeFrom(byteBuffer);
132
- for (PhoneMetadata metadata : shortNumberMetadata.metadata) {
153
+ String fileName = SHORT_NUMBER_METADATA_FILE_PREFIX + "_" + regionCode;
154
+ InputStream source = MetadataManager.class.getResourceAsStream(fileName);
155
+ if (source == null) {
156
+ // Sanity check; this should not happen since we only load things based on the expectation
157
+ // that they are present, by checking the map of available data first.
158
+ throw new IllegalStateException("missing metadata: " + fileName);
159
+ }
160
+ PhoneMetadataCollection shortNumberData =
161
+ loadMetadataAndCloseInput(source, DEFAULT_BUFFER_SIZE);
162
+ for (PhoneMetadata metadata : shortNumberData.metadata) {
133
163
  regionCodeToShortNumberMetadataMap.put(regionCode, metadata);
134
- }
135
- } catch (IOException e) {
136
- LOGGER.log(Level.WARNING, e.toString());
137
- } finally {
138
- close(in);
139
164
  }
140
165
  }
141
166
 
@@ -19,9 +19,7 @@ package com.google.i18n.phonenumbers;
19
19
  import com.google.i18n.phonenumbers.nano.Phonemetadata.PhoneMetadata;
20
20
  import com.google.i18n.phonenumbers.nano.Phonemetadata.PhoneMetadataCollection;
21
21
 
22
- import java.io.IOException;
23
22
  import java.io.InputStream;
24
- import java.io.ObjectInputStream;
25
23
  import java.util.concurrent.ConcurrentHashMap;
26
24
  import java.util.List;
27
25
  import java.util.logging.Level;
@@ -114,43 +112,22 @@ final class MultiFileMetadataSourceImpl implements MetadataSource {
114
112
  String fileName = filePrefix + "_" + key;
115
113
  InputStream source = metadataLoader.loadMetadata(fileName);
116
114
  if (source == null) {
115
+ // Sanity check; this should not happen since we only load things based on the expectation
116
+ // that they are present, by checking the map of available data first.
117
117
  throw new IllegalStateException("missing metadata: " + fileName);
118
118
  }
119
- PhoneMetadataCollection metadataCollection = loadMetadataAndCloseInput(source);
120
- PhoneMetadata[] metadataList = metadataCollection.metadata;
121
- if (metadataList.length == 0) {
119
+ PhoneMetadataCollection metadataCollection =
120
+ MetadataManager.loadMetadataAndCloseInput(source, MetadataManager.DEFAULT_BUFFER_SIZE);
121
+ PhoneMetadata[] metadatas = metadataCollection.metadata;
122
+ if (metadatas.length == 0) {
123
+ // Sanity check; this should not happen since we build with non-empty metadata.
122
124
  throw new IllegalStateException("empty metadata: " + fileName);
123
125
  }
124
- if (metadataList.length > 1) {
126
+ if (metadatas.length > 1) {
125
127
  logger.log(Level.WARNING, "invalid metadata (too many entries): " + fileName);
126
128
  }
127
- PhoneMetadata metadata = metadataList[0];
129
+ PhoneMetadata metadata = metadatas[0];
128
130
  PhoneMetadata oldValue = map.putIfAbsent(key, metadata);
129
131
  return (oldValue != null) ? oldValue : metadata;
130
132
  }
131
-
132
- /**
133
- * Loads and returns the metadata protocol buffer from the given stream and closes the stream.
134
- */
135
- private static PhoneMetadataCollection loadMetadataAndCloseInput(InputStream source) {
136
- // The size of the byte buffer used for deserializing the phone number metadata files for each
137
- // region.
138
- final int MULTI_FILE_BUFFER_SIZE = 16 * 1024;
139
-
140
- try {
141
- // Read in metadata for each region.
142
- PhoneMetadataCollection metadataCollection = new PhoneMetadataCollection();
143
- metadataCollection.mergeFrom(MetadataManager.convertStreamToByteBuffer(
144
- new ObjectInputStream(source), MULTI_FILE_BUFFER_SIZE));
145
- return metadataCollection;
146
- } catch (IOException e) {
147
- throw new RuntimeException("cannot load/parse metadata", e);
148
- } finally {
149
- try {
150
- source.close();
151
- } catch (IOException e) {
152
- logger.log(Level.WARNING, "error closing input stream (ignored)", e);
153
- }
154
- }
155
- }
156
133
  }
@@ -88,9 +88,17 @@ public class PhoneNumberUtil {
88
88
  // be the length of the area code plus the length of the mobile token.
89
89
  private static final Map<Integer, String> MOBILE_TOKEN_MAPPINGS;
90
90
 
91
+ // Set of country codes that have geographically assigned mobile numbers (see GEO_MOBILE_COUNTRIES
92
+ // below) which are not based on *area codes*. For example, in China mobile numbers start with a
93
+ // carrier indicator, and beyond that are geographically assigned: this carrier indicator is not
94
+ // considered to be an area code.
95
+ private static final Set<Integer> GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES;
96
+
91
97
  // Set of country calling codes that have geographically assigned mobile numbers. This may not be
92
98
  // complete; we add calling codes case by case, as we find geographical mobile numbers or hear
93
- // from user reports.
99
+ // from user reports. Note that countries like the US, where we can't distinguish between
100
+ // fixed-line or mobile numbers, are not listed here, since we consider FIXED_LINE_OR_MOBILE to be
101
+ // a possibly geographically-related type anyway (like FIXED_LINE).
94
102
  private static final Set<Integer> GEO_MOBILE_COUNTRIES;
95
103
 
96
104
  // The PLUS_SIGN signifies the international prefix.
@@ -124,10 +132,17 @@ public class PhoneNumberUtil {
124
132
  mobileTokenMap.put(54, "9");
125
133
  MOBILE_TOKEN_MAPPINGS = Collections.unmodifiableMap(mobileTokenMap);
126
134
 
135
+ HashSet<Integer> geoMobileCountriesWithoutMobileAreaCodes = new HashSet<Integer>();
136
+ geoMobileCountriesWithoutMobileAreaCodes.add(86); // China
137
+ GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES =
138
+ Collections.unmodifiableSet(geoMobileCountriesWithoutMobileAreaCodes);
139
+
127
140
  HashSet<Integer> geoMobileCountries = new HashSet<Integer>();
128
141
  geoMobileCountries.add(52); // Mexico
129
142
  geoMobileCountries.add(54); // Argentina
130
143
  geoMobileCountries.add(55); // Brazil
144
+ geoMobileCountries.add(62); // Indonesia: some prefixes only (fixed CMDA wireless)
145
+ geoMobileCountries.addAll(geoMobileCountriesWithoutMobileAreaCodes);
131
146
  GEO_MOBILE_COUNTRIES = Collections.unmodifiableSet(geoMobileCountries);
132
147
 
133
148
  // Simple ASCII digits map used to populate ALPHA_PHONE_MAPPINGS and
@@ -802,7 +817,17 @@ public class PhoneNumberUtil {
802
817
  return 0;
803
818
  }
804
819
 
805
- if (!isNumberGeographical(number)) {
820
+ PhoneNumberType type = getNumberType(number);
821
+ int countryCallingCode = number.getCountryCode();
822
+ if (type == PhoneNumberType.MOBILE
823
+ // Note this is a rough heuristic; it doesn't cover Indonesia well, for example, where area
824
+ // codes are present for some mobile phones but not for others. We have no better way of
825
+ // representing this in the metadata at this point.
826
+ && GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES.contains(countryCallingCode)) {
827
+ return 0;
828
+ }
829
+
830
+ if (!isNumberGeographical(type, countryCallingCode)) {
806
831
  return 0;
807
832
  }
808
833
 
@@ -1017,18 +1042,22 @@ public class PhoneNumberUtil {
1017
1042
  * Tests whether a phone number has a geographical association. It checks if the number is
1018
1043
  * associated to a certain region in the country where it belongs to. Note that this doesn't
1019
1044
  * verify if the number is actually in use.
1020
- *
1021
- * A similar method is implemented as PhoneNumberOfflineGeocoder.canBeGeocoded, which performs a
1022
- * looser check, since it only prevents cases where prefixes overlap for geocodable and
1023
- * non-geocodable numbers. Also, if new phone number types were added, we should check if this
1024
- * other method should be updated too.
1025
1045
  */
1026
- boolean isNumberGeographical(PhoneNumber phoneNumber) {
1027
- PhoneNumberType numberType = getNumberType(phoneNumber);
1046
+ public boolean isNumberGeographical(PhoneNumber phoneNumber) {
1047
+ return isNumberGeographical(getNumberType(phoneNumber), phoneNumber.getCountryCode());
1048
+ }
1028
1049
 
1050
+ /**
1051
+ * Tests whether a phone number has a geographical association, as represented by its type and the
1052
+ * country it belongs to.
1053
+ *
1054
+ * This version of isNumberGeographical exists since calculating the phone number type is
1055
+ * expensive; if we have already done this, we don't want to do it again.
1056
+ */
1057
+ public boolean isNumberGeographical(PhoneNumberType numberType, int countryCallingCode) {
1029
1058
  return numberType == PhoneNumberType.FIXED_LINE
1030
1059
  || numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE
1031
- || (GEO_MOBILE_COUNTRIES.contains(phoneNumber.getCountryCode())
1060
+ || (GEO_MOBILE_COUNTRIES.contains(countryCallingCode)
1032
1061
  && numberType == PhoneNumberType.MOBILE);
1033
1062
  }
1034
1063
 
@@ -2772,7 +2801,7 @@ public class PhoneNumberUtil {
2772
2801
  * Parses a string and returns it as a phone number in proto buffer format. The method is quite
2773
2802
  * lenient and looks for a number in the input text (raw input) and does not check whether the
2774
2803
  * string is definitely only a phone number. To do this, it ignores punctuation and white-space,
2775
- * as well as any text before the number (e.g. a leading Tel: ) and trims the non-number bits.
2804
+ * as well as any text before the number (e.g. a leading "Tel: ") and trims the non-number bits.
2776
2805
  * It will accept a number in any format (E164, national, international etc), assuming it can be
2777
2806
  * interpreted with the defaultRegion supplied. It also attempts to convert any alpha characters
2778
2807
  * into digits if it thinks this is a vanity number of the type "1800 MICROSOFT".
@@ -19,14 +19,11 @@ package com.google.i18n.phonenumbers;
19
19
  import com.google.i18n.phonenumbers.nano.Phonemetadata.PhoneMetadata;
20
20
  import com.google.i18n.phonenumbers.nano.Phonemetadata.PhoneMetadataCollection;
21
21
 
22
- import java.io.IOException;
23
22
  import java.io.InputStream;
24
- import java.io.ObjectInputStream;
25
23
  import java.util.Collections;
26
24
  import java.util.HashMap;
27
25
  import java.util.List;
28
26
  import java.util.Map;
29
- import java.util.logging.Level;
30
27
  import java.util.logging.Logger;
31
28
 
32
29
  /**
@@ -97,58 +94,29 @@ final class SingleFileMetadataSourceImpl implements MetadataSource {
97
94
  void loadMetadataFromFile() {
98
95
  InputStream source = metadataLoader.loadMetadata(fileName);
99
96
  if (source == null) {
100
- logger.log(Level.SEVERE, "missing metadata: " + fileName);
97
+ // This should not happen since clients shouldn't be using this implementation directly.
98
+ // The single file implementation is experimental, only for when the jars contain a single
99
+ // file with all regions' metadata. Currently we do not release such jars.
100
+ // TODO(b/30807096): Get the MetadataManager to decide whether to use this or the multi file
101
+ // loading depending on what data is available in the jar.
101
102
  throw new IllegalStateException("missing metadata: " + fileName);
102
103
  }
103
- try {
104
- PhoneMetadataCollection metadataCollection =
105
- loadMetadataAndCloseInput(new ObjectInputStream(source));
106
- PhoneMetadata[] metadataList = metadataCollection.metadata;
107
- if (metadataList.length == 0) {
108
- logger.log(Level.SEVERE, "empty metadata: " + fileName);
109
- throw new IllegalStateException("empty metadata: " + fileName);
110
- }
111
- for (PhoneMetadata metadata : metadataList) {
112
- String regionCode = metadata.id;
113
- int countryCallingCode = metadata.countryCode;
114
- boolean isNonGeoRegion = PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode);
115
- if (isNonGeoRegion) {
116
- countryCodeToNonGeographicalMetadataMap.put(countryCallingCode, metadata);
117
- } else {
118
- regionToMetadataMap.put(regionCode, metadata);
119
- }
120
- }
121
- } catch (IOException e) {
122
- logger.log(Level.SEVERE, "cannot load/parse metadata: " + fileName, e);
123
- throw new RuntimeException("cannot load/parse metadata: " + fileName, e);
104
+ PhoneMetadataCollection metadataCollection =
105
+ MetadataManager.loadMetadataAndCloseInput(source, MetadataManager.ALL_REGIONS_BUFFER_SIZE);
106
+ PhoneMetadata[] metadatas = metadataCollection.metadata;
107
+ if (metadatas.length == 0) {
108
+ // This should not happen since clients shouldn't be using this implementation!
109
+ throw new IllegalStateException("empty metadata: " + fileName);
124
110
  }
125
- }
126
-
127
- /**
128
- * Loads the metadata protocol buffer from the given stream and closes the stream afterwards. Any
129
- * exceptions that occur while reading or closing the stream are ignored.
130
- *
131
- * @param source the non-null stream from which metadata is to be read.
132
- * @return the loaded metadata protocol buffer.
133
- */
134
- private static PhoneMetadataCollection loadMetadataAndCloseInput(ObjectInputStream source) {
135
- // The size of the byte buffer for deserializing the single nano metadata file which holds
136
- // metadata for all regions.
137
- final int SINGLE_FILE_BUFFER_SIZE = 256 * 1024;
138
-
139
- PhoneMetadataCollection metadataCollection = new PhoneMetadataCollection();
140
- try {
141
- metadataCollection.mergeFrom(
142
- MetadataManager.convertStreamToByteBuffer(source, SINGLE_FILE_BUFFER_SIZE));
143
- } catch (IOException e) {
144
- logger.log(Level.WARNING, "error reading input (ignored)", e);
145
- } finally {
146
- try {
147
- source.close();
148
- } catch (IOException e) {
149
- logger.log(Level.WARNING, "error closing input stream (ignored)", e);
111
+ for (PhoneMetadata metadata : metadatas) {
112
+ String regionCode = metadata.id;
113
+ int countryCallingCode = metadata.countryCode;
114
+ boolean isNonGeoRegion = PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode);
115
+ if (isNonGeoRegion) {
116
+ countryCodeToNonGeographicalMetadataMap.put(countryCallingCode, metadata);
117
+ } else {
118
+ regionToMetadataMap.put(regionCode, metadata);
150
119
  }
151
120
  }
152
- return metadataCollection;
153
121
  }
154
122
  }
@@ -235,12 +235,16 @@ public class PhoneNumberUtilTest extends TestMetadataTestCase {
235
235
  // Google London, which has area code "20".
236
236
  assertEquals(2, phoneUtil.getLengthOfGeographicalAreaCode(GB_NUMBER));
237
237
 
238
- // A UK mobile phone, which has no area code.
238
+ // A mobile number in the UK does not have an area code (by default, mobile numbers do not,
239
+ // unless they have been added to our list of exceptions).
239
240
  assertEquals(0, phoneUtil.getLengthOfGeographicalAreaCode(GB_MOBILE));
240
241
 
241
242
  // Google Buenos Aires, which has area code "11".
242
243
  assertEquals(2, phoneUtil.getLengthOfGeographicalAreaCode(AR_NUMBER));
243
244
 
245
+ // A mobile number in Argentina also has an area code.
246
+ assertEquals(3, phoneUtil.getLengthOfGeographicalAreaCode(AR_MOBILE));
247
+
244
248
  // Google Sydney, which has area code "2".
245
249
  assertEquals(1, phoneUtil.getLengthOfGeographicalAreaCode(AU_NUMBER));
246
250
 
@@ -255,6 +259,10 @@ public class PhoneNumberUtilTest extends TestMetadataTestCase {
255
259
 
256
260
  // An international toll free number, which has no area code.
257
261
  assertEquals(0, phoneUtil.getLengthOfGeographicalAreaCode(INTERNATIONAL_TOLL_FREE));
262
+
263
+ // A mobile number from China is geographical, but does not have an area code.
264
+ PhoneNumber cnMobile = new PhoneNumber().setCountryCode(86).setNationalNumber(18912341234L);
265
+ assertEquals(0, phoneUtil.getLengthOfGeographicalAreaCode(cnMobile));
258
266
  }
259
267
 
260
268
  public void testGetLengthOfNationalDestinationCode() {
@@ -291,6 +299,11 @@ public class PhoneNumberUtilTest extends TestMetadataTestCase {
291
299
 
292
300
  // An international toll free number, which has NDC "1234".
293
301
  assertEquals(4, phoneUtil.getLengthOfNationalDestinationCode(INTERNATIONAL_TOLL_FREE));
302
+
303
+ // A mobile number from China is geographical, but does not have an area code: however it still
304
+ // can be considered to have a national destination code.
305
+ PhoneNumber cnMobile = new PhoneNumber().setCountryCode(86).setNationalNumber(18912341234L);
306
+ assertEquals(3, phoneUtil.getLengthOfNationalDestinationCode(cnMobile));
294
307
  }
295
308
 
296
309
  public void testGetCountryMobileToken() {