| /* GENERATED SOURCE. DO NOT MODIFY. */ |
| /* |
| * Copyright (C) 2011 The Libphonenumber Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.i18n.phonenumbers.geocoding; |
| |
| import com.android.i18n.phonenumbers.NumberParseException; |
| import com.android.i18n.phonenumbers.PhoneNumberUtil; |
| import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberType; |
| import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; |
| import com.android.i18n.phonenumbers.prefixmapper.PrefixFileReader; |
| |
| import java.util.List; |
| import java.util.Locale; |
| |
| /** |
| * An offline geocoder which provides geographical information related to a phone number. |
| * |
| * @author Shaopeng Jia |
| * @hide This class is not part of the Android public SDK API |
| */ |
| public class PhoneNumberOfflineGeocoder { |
| private static PhoneNumberOfflineGeocoder instance = null; |
| private static final String MAPPING_DATA_DIRECTORY = |
| "/com/android/i18n/phonenumbers/geocoding/data/"; |
| private PrefixFileReader prefixFileReader = null; |
| |
| private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); |
| |
| // @VisibleForTesting |
| PhoneNumberOfflineGeocoder(String phonePrefixDataDirectory) { |
| prefixFileReader = new PrefixFileReader(phonePrefixDataDirectory); |
| } |
| |
| /** |
| * Gets a {@link PhoneNumberOfflineGeocoder} instance to carry out international phone number |
| * geocoding. |
| * |
| * <p> The {@link PhoneNumberOfflineGeocoder} is implemented as a singleton. Therefore, calling |
| * this method multiple times will only result in one instance being created. |
| * |
| * @return a {@link PhoneNumberOfflineGeocoder} instance |
| */ |
| @android.compat.annotation.UnsupportedAppUsage |
| public static synchronized PhoneNumberOfflineGeocoder getInstance() { |
| if (instance == null) { |
| instance = new PhoneNumberOfflineGeocoder(MAPPING_DATA_DIRECTORY); |
| } |
| return instance; |
| } |
| |
| /** |
| * Returns the customary display name in the given language for the given territory the phone |
| * number is from. If it could be from many territories, nothing is returned. |
| */ |
| private String getCountryNameForNumber(PhoneNumber number, Locale language) { |
| List<String> regionCodes = |
| phoneUtil.getRegionCodesForCountryCode(number.getCountryCode()); |
| if (regionCodes.size() == 1) { |
| return getRegionDisplayName(regionCodes.get(0), language); |
| } else { |
| String regionWhereNumberIsValid = "ZZ"; |
| for (String regionCode : regionCodes) { |
| if (phoneUtil.isValidNumberForRegion(number, regionCode)) { |
| // If the number has already been found valid for one region, then we don't know which |
| // region it belongs to so we return nothing. |
| if (!regionWhereNumberIsValid.equals("ZZ")) { |
| return ""; |
| } |
| regionWhereNumberIsValid = regionCode; |
| } |
| } |
| return getRegionDisplayName(regionWhereNumberIsValid, language); |
| } |
| } |
| |
| /** |
| * Returns the customary display name in the given language for the given region. |
| */ |
| private String getRegionDisplayName(String regionCode, Locale language) { |
| return (regionCode == null || regionCode.equals("ZZ") |
| || regionCode.equals(PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY)) |
| ? "" : new Locale("", regionCode).getDisplayCountry(language); |
| } |
| |
| /** |
| * Returns a text description for the given phone number, in the language provided. The |
| * description might consist of the name of the country where the phone number is from, or the |
| * name of the geographical area the phone number is from if more detailed information is |
| * available. |
| * |
| * <p>This method assumes the validity of the number passed in has already been checked, and that |
| * the number is suitable for geocoding. We consider fixed-line and mobile numbers possible |
| * candidates for geocoding. |
| * |
| * @param number a valid phone number for which we want to get a text description |
| * @param languageCode the language code for which the description should be written |
| * @return a text description for the given language code for the given phone number, or an |
| * empty string if the number could come from multiple countries, or the country code is |
| * in fact invalid |
| */ |
| public String getDescriptionForValidNumber(PhoneNumber number, Locale languageCode) { |
| String langStr = languageCode.getLanguage(); |
| String scriptStr = ""; // No script is specified |
| String regionStr = languageCode.getCountry(); |
| |
| String areaDescription; |
| String mobileToken = PhoneNumberUtil.getCountryMobileToken(number.getCountryCode()); |
| String nationalNumber = phoneUtil.getNationalSignificantNumber(number); |
| if (!mobileToken.equals("") && nationalNumber.startsWith(mobileToken)) { |
| // In some countries, eg. Argentina, mobile numbers have a mobile token before the national |
| // destination code, this should be removed before geocoding. |
| nationalNumber = nationalNumber.substring(mobileToken.length()); |
| String region = phoneUtil.getRegionCodeForCountryCode(number.getCountryCode()); |
| PhoneNumber copiedNumber; |
| try { |
| copiedNumber = phoneUtil.parse(nationalNumber, region); |
| } catch (NumberParseException e) { |
| // If this happens, just reuse what we had. |
| copiedNumber = number; |
| } |
| areaDescription = prefixFileReader.getDescriptionForNumber(copiedNumber, langStr, scriptStr, |
| regionStr); |
| } else { |
| areaDescription = prefixFileReader.getDescriptionForNumber(number, langStr, scriptStr, |
| regionStr); |
| } |
| return (areaDescription.length() > 0) |
| ? areaDescription : getCountryNameForNumber(number, languageCode); |
| } |
| |
| /** |
| * As per {@link #getDescriptionForValidNumber(PhoneNumber, Locale)} but also considers the |
| * region of the user. If the phone number is from the same region as the user, only a lower-level |
| * description will be returned, if one exists. Otherwise, the phone number's region will be |
| * returned, with optionally some more detailed information. |
| * |
| * <p>For example, for a user from the region "US" (United States), we would show "Mountain View, |
| * CA" for a particular number, omitting the United States from the description. For a user from |
| * the United Kingdom (region "GB"), for the same number we may show "Mountain View, CA, United |
| * States" or even just "United States". |
| * |
| * <p>This method assumes the validity of the number passed in has already been checked. |
| * |
| * @param number the phone number for which we want to get a text description |
| * @param languageCode the language code for which the description should be written |
| * @param userRegion the region code for a given user. This region will be omitted from the |
| * description if the phone number comes from this region. It should be a two-letter |
| * upper-case CLDR region code. |
| * @return a text description for the given language code for the given phone number, or an |
| * empty string if the number could come from multiple countries, or the country code is |
| * in fact invalid |
| */ |
| public String getDescriptionForValidNumber(PhoneNumber number, Locale languageCode, |
| String userRegion) { |
| // If the user region matches the number's region, then we just show the lower-level |
| // description, if one exists - if no description exists, we will show the region(country) name |
| // for the number. |
| String regionCode = phoneUtil.getRegionCodeForNumber(number); |
| if (userRegion.equals(regionCode)) { |
| return getDescriptionForValidNumber(number, languageCode); |
| } |
| // Otherwise, we just show the region(country) name for now. |
| return getRegionDisplayName(regionCode, languageCode); |
| // TODO: Concatenate the lower-level and country-name information in an appropriate |
| // way for each language. |
| } |
| |
| /** |
| * As per {@link #getDescriptionForValidNumber(PhoneNumber, Locale)} but explicitly checks |
| * the validity of the number passed in. |
| * |
| * @param number the phone number for which we want to get a text description |
| * @param languageCode the language code for which the description should be written |
| * @return a text description for the given language code for the given phone number, or empty |
| * string if the number passed in is invalid or could belong to multiple countries |
| */ |
| @android.compat.annotation.UnsupportedAppUsage |
| public String getDescriptionForNumber(PhoneNumber number, Locale languageCode) { |
| PhoneNumberType numberType = phoneUtil.getNumberType(number); |
| if (numberType == PhoneNumberType.UNKNOWN) { |
| return ""; |
| } else if (!phoneUtil.isNumberGeographical(numberType, number.getCountryCode())) { |
| return getCountryNameForNumber(number, languageCode); |
| } |
| return getDescriptionForValidNumber(number, languageCode); |
| } |
| |
| /** |
| * As per {@link #getDescriptionForValidNumber(PhoneNumber, Locale, String)} but |
| * explicitly checks the validity of the number passed in. |
| * |
| * @param number the phone number for which we want to get a text description |
| * @param languageCode the language code for which the description should be written |
| * @param userRegion the region code for a given user. This region will be omitted from the |
| * description if the phone number comes from this region. It should be a two-letter |
| * upper-case CLDR region code. |
| * @return a text description for the given language code for the given phone number, or empty |
| * string if the number passed in is invalid or could belong to multiple countries |
| */ |
| public String getDescriptionForNumber(PhoneNumber number, Locale languageCode, |
| String userRegion) { |
| PhoneNumberType numberType = phoneUtil.getNumberType(number); |
| if (numberType == PhoneNumberType.UNKNOWN) { |
| return ""; |
| } else if (!phoneUtil.isNumberGeographical(numberType, number.getCountryCode())) { |
| return getCountryNameForNumber(number, languageCode); |
| } |
| return getDescriptionForValidNumber(number, languageCode, userRegion); |
| } |
| } |