phonelib 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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() {