• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Libphonenumber Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.i18n.phonenumbers.prefixmapper;
18 
19 import com.google.i18n.phonenumbers.MetadataLoader;
20 import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
21 
22 import com.google.i18n.phonenumbers.metadata.DefaultMetadataDependenciesProvider;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.ObjectInputStream;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30 
31 /**
32  * A helper class doing file handling and lookup of phone number prefix mappings.
33  *
34  * @author Shaopeng Jia
35  */
36 public class PrefixFileReader {
37   private static final Logger logger = Logger.getLogger(PrefixFileReader.class.getName());
38 
39   private final String phonePrefixDataDirectory;
40   // The mappingFileProvider knows for which combination of countryCallingCode and language a phone
41   // prefix mapping file is available in the file system, so that a file can be loaded when needed.
42   private MappingFileProvider mappingFileProvider = new MappingFileProvider();
43   // A mapping from countryCallingCode_lang to the corresponding phone prefix map that has been
44   // loaded.
45   private Map<String, PhonePrefixMap> availablePhonePrefixMaps = new HashMap<>();
46   private final MetadataLoader metadataLoader;
47 
PrefixFileReader(String phonePrefixDataDirectory)48   public PrefixFileReader(String phonePrefixDataDirectory) {
49     this.phonePrefixDataDirectory = phonePrefixDataDirectory;
50     this.metadataLoader = DefaultMetadataDependenciesProvider.getInstance().getMetadataLoader();
51     loadMappingFileProvider();
52   }
53 
loadMappingFileProvider()54   private void loadMappingFileProvider() {
55     InputStream source = metadataLoader.loadMetadata(phonePrefixDataDirectory + "config");
56     ObjectInputStream in = null;
57     try {
58       in = new ObjectInputStream(source);
59       mappingFileProvider.readExternal(in);
60     } catch (IOException e) {
61       logger.log(Level.WARNING, e.toString());
62     } finally {
63       close(in);
64     }
65   }
66 
getPhonePrefixDescriptions( int prefixMapKey, String language, String script, String region)67   private PhonePrefixMap getPhonePrefixDescriptions(
68       int prefixMapKey, String language, String script, String region) {
69     String fileName = mappingFileProvider.getFileName(prefixMapKey, language, script, region);
70     if (fileName.length() == 0) {
71       return null;
72     }
73     if (!availablePhonePrefixMaps.containsKey(fileName)) {
74       loadPhonePrefixMapFromFile(fileName);
75     }
76     return availablePhonePrefixMaps.get(fileName);
77   }
78 
loadPhonePrefixMapFromFile(String fileName)79   private void loadPhonePrefixMapFromFile(String fileName) {
80     InputStream source = metadataLoader.loadMetadata(phonePrefixDataDirectory + fileName);
81     ObjectInputStream in = null;
82     try {
83       in = new ObjectInputStream(source);
84       PhonePrefixMap map = new PhonePrefixMap();
85       map.readExternal(in);
86       availablePhonePrefixMaps.put(fileName, map);
87     } catch (IOException e) {
88       logger.log(Level.WARNING, e.toString());
89     } finally {
90       close(in);
91     }
92   }
93 
close(InputStream in)94   private static void close(InputStream in) {
95     if (in != null) {
96       try {
97         in.close();
98       } catch (IOException e) {
99         logger.log(Level.WARNING, e.toString());
100       }
101     }
102   }
103 
104   /**
105    * Returns a text description in the given language for the given phone number.
106    *
107    * @param number  the phone number for which we want to get a text description
108    * @param language  two or three-letter lowercase ISO language codes as defined by ISO 639. Note
109    *     that where two different language codes exist (e.g. 'he' and 'iw' for Hebrew) we use the
110    *     one that Java/Android canonicalized on ('iw' in this case).
111    * @param script  four-letter titlecase (the first letter is uppercase and the rest of the letters
112    *     are lowercase) ISO script code as defined in ISO 15924
113    * @param region  two-letter uppercase ISO country code as defined by ISO 3166-1
114    * @return  a text description in the given language for the given phone number, or an empty
115    *     string if a description is not available
116    */
getDescriptionForNumber( PhoneNumber number, String language, String script, String region)117   public String getDescriptionForNumber(
118       PhoneNumber number, String language, String script, String region) {
119     int countryCallingCode = number.getCountryCode();
120     // As the NANPA data is split into multiple files covering 3-digit areas, use a phone number
121     // prefix of 4 digits for NANPA instead, e.g. 1650.
122     int phonePrefix = (countryCallingCode != 1)
123         ? countryCallingCode : (1000 + (int) (number.getNationalNumber() / 10000000));
124     PhonePrefixMap phonePrefixDescriptions =
125         getPhonePrefixDescriptions(phonePrefix, language, script, region);
126     String description = (phonePrefixDescriptions != null)
127         ? phonePrefixDescriptions.lookup(number) : null;
128     // When a location is not available in the requested language, fall back to English.
129     if ((description == null || description.length() == 0) && mayFallBackToEnglish(language)) {
130       PhonePrefixMap defaultMap = getPhonePrefixDescriptions(phonePrefix, "en", "", "");
131       if (defaultMap == null) {
132         return "";
133       }
134       description = defaultMap.lookup(number);
135     }
136     return description != null ? description : "";
137   }
138 
mayFallBackToEnglish(String lang)139   private boolean mayFallBackToEnglish(String lang) {
140     // Don't fall back to English if the requested language is among the following:
141     // - Chinese
142     // - Japanese
143     // - Korean
144     return !lang.equals("zh") && !lang.equals("ja") && !lang.equals("ko");
145   }
146 }
147