1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 /* 3 * Copyright (C) 2012 The Libphonenumber Authors 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.i18n.phonenumbers; 19 20 import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberType; 21 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; 22 import com.android.i18n.phonenumbers.prefixmapper.PrefixTimeZonesMap; 23 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.io.ObjectInputStream; 27 import java.util.ArrayList; 28 import java.util.Collections; 29 import java.util.List; 30 import java.util.logging.Level; 31 import java.util.logging.Logger; 32 33 /** 34 * An offline mapper from phone numbers to time zones. 35 * @hide This class is not part of the Android public SDK API 36 */ 37 public class PhoneNumberToTimeZonesMapper { 38 private static final String MAPPING_DATA_DIRECTORY = 39 "/com/android/i18n/phonenumbers/timezones/data/"; 40 private static final String MAPPING_DATA_FILE_NAME = "map_data"; 41 // This is defined by ICU as the unknown time zone. 42 private static final String UNKNOWN_TIMEZONE = "Etc/Unknown"; 43 // A list with the ICU unknown time zone as single element. 44 // @VisibleForTesting 45 static final List<String> UNKNOWN_TIME_ZONE_LIST = new ArrayList<String>(1); 46 static { 47 UNKNOWN_TIME_ZONE_LIST.add(UNKNOWN_TIMEZONE); 48 } 49 50 private static final Logger logger = 51 Logger.getLogger(PhoneNumberToTimeZonesMapper.class.getName()); 52 53 private PrefixTimeZonesMap prefixTimeZonesMap = null; 54 55 // @VisibleForTesting PhoneNumberToTimeZonesMapper(String prefixTimeZonesMapDataDirectory)56 PhoneNumberToTimeZonesMapper(String prefixTimeZonesMapDataDirectory) { 57 this.prefixTimeZonesMap = loadPrefixTimeZonesMapFromFile( 58 prefixTimeZonesMapDataDirectory + MAPPING_DATA_FILE_NAME); 59 } 60 PhoneNumberToTimeZonesMapper(PrefixTimeZonesMap prefixTimeZonesMap)61 private PhoneNumberToTimeZonesMapper(PrefixTimeZonesMap prefixTimeZonesMap) { 62 this.prefixTimeZonesMap = prefixTimeZonesMap; 63 } 64 loadPrefixTimeZonesMapFromFile(String path)65 private static PrefixTimeZonesMap loadPrefixTimeZonesMapFromFile(String path) { 66 InputStream source = PhoneNumberToTimeZonesMapper.class.getResourceAsStream(path); 67 ObjectInputStream in = null; 68 PrefixTimeZonesMap map = new PrefixTimeZonesMap(); 69 try { 70 in = new ObjectInputStream(source); 71 map.readExternal(in); 72 } catch (IOException e) { 73 logger.log(Level.WARNING, e.toString()); 74 } finally { 75 close(in); 76 } 77 return map; 78 } 79 close(InputStream in)80 private static void close(InputStream in) { 81 if (in != null) { 82 try { 83 in.close(); 84 } catch (IOException e) { 85 logger.log(Level.WARNING, e.toString()); 86 } 87 } 88 } 89 90 /** 91 * Helper class used for lazy instantiation of a PhoneNumberToTimeZonesMapper. This also loads the 92 * map data in a thread-safe way. 93 */ 94 private static class LazyHolder { 95 private static final PhoneNumberToTimeZonesMapper INSTANCE; 96 static { 97 PrefixTimeZonesMap map = 98 loadPrefixTimeZonesMapFromFile(MAPPING_DATA_DIRECTORY + MAPPING_DATA_FILE_NAME); 99 INSTANCE = new PhoneNumberToTimeZonesMapper(map); 100 } 101 } 102 103 /** 104 * Gets a {@link PhoneNumberToTimeZonesMapper} instance. 105 * 106 * <p> The {@link PhoneNumberToTimeZonesMapper} is implemented as a singleton. Therefore, calling 107 * this method multiple times will only result in one instance being created. 108 * 109 * @return a {@link PhoneNumberToTimeZonesMapper} instance 110 */ getInstance()111 public static synchronized PhoneNumberToTimeZonesMapper getInstance() { 112 return LazyHolder.INSTANCE; 113 } 114 115 /** 116 * Returns a list of time zones to which a phone number belongs. 117 * 118 * <p>This method assumes the validity of the number passed in has already been checked, and that 119 * the number is geo-localizable. We consider fixed-line and mobile numbers possible candidates 120 * for geo-localization. 121 * 122 * @param number a valid phone number for which we want to get the time zones to which it belongs 123 * @return a list of the corresponding time zones or a single element list with the default 124 * unknown time zone if no other time zone was found or if the number was invalid 125 */ getTimeZonesForGeographicalNumber(PhoneNumber number)126 public List<String> getTimeZonesForGeographicalNumber(PhoneNumber number) { 127 return getTimeZonesForGeocodableNumber(number); 128 } 129 130 /** 131 * As per {@link #getTimeZonesForGeographicalNumber(PhoneNumber)} but explicitly checks 132 * the validity of the number passed in. 133 * 134 * @param number the phone number for which we want to get the time zones to which it belongs 135 * @return a list of the corresponding time zones or a single element list with the default 136 * unknown time zone if no other time zone was found or if the number was invalid 137 */ getTimeZonesForNumber(PhoneNumber number)138 public List<String> getTimeZonesForNumber(PhoneNumber number) { 139 PhoneNumberType numberType = PhoneNumberUtil.getInstance().getNumberType(number); 140 if (numberType == PhoneNumberType.UNKNOWN) { 141 return UNKNOWN_TIME_ZONE_LIST; 142 } else if (!PhoneNumberUtil.getInstance().isNumberGeographical( 143 numberType, number.getCountryCode())) { 144 return getCountryLevelTimeZonesforNumber(number); 145 } 146 return getTimeZonesForGeographicalNumber(number); 147 } 148 149 /** 150 * Returns a String with the ICU unknown time zone. 151 */ getUnknownTimeZone()152 public static String getUnknownTimeZone() { 153 return UNKNOWN_TIMEZONE; 154 } 155 156 /** 157 * Returns a list of time zones to which a geocodable phone number belongs. 158 * 159 * @param number the phone number for which we want to get the time zones to which it belongs 160 * @return the list of corresponding time zones or a single element list with the default 161 * unknown time zone if no other time zone was found or if the number was invalid 162 */ getTimeZonesForGeocodableNumber(PhoneNumber number)163 private List<String> getTimeZonesForGeocodableNumber(PhoneNumber number) { 164 List<String> timezones = prefixTimeZonesMap.lookupTimeZonesForNumber(number); 165 return Collections.unmodifiableList(timezones.isEmpty() ? UNKNOWN_TIME_ZONE_LIST 166 : timezones); 167 } 168 169 /** 170 * Returns the list of time zones corresponding to the country calling code of {@code number}. 171 * 172 * @param number the phone number to look up 173 * @return the list of corresponding time zones or a single element list with the default 174 * unknown time zone if no other time zone was found 175 */ getCountryLevelTimeZonesforNumber(PhoneNumber number)176 private List<String> getCountryLevelTimeZonesforNumber(PhoneNumber number) { 177 List<String> timezones = prefixTimeZonesMap.lookupCountryLevelTimeZonesForNumber(number); 178 return Collections.unmodifiableList(timezones.isEmpty() ? UNKNOWN_TIME_ZONE_LIST 179 : timezones); 180 } 181 } 182