Home | History | Annotate | Download | only in geocoding
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 /*
      3  * Copyright (C) 2011 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.geocoding;
     19 
     20 import com.android.i18n.phonenumbers.NumberParseException;
     21 import com.android.i18n.phonenumbers.PhoneNumberUtil;
     22 import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberType;
     23 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
     24 import com.android.i18n.phonenumbers.prefixmapper.PrefixFileReader;
     25 
     26 import java.util.List;
     27 import java.util.Locale;
     28 
     29 /**
     30  * An offline geocoder which provides geographical information related to a phone number.
     31  *
     32  * @author Shaopeng Jia
     33  * @hide This class is not part of the Android public SDK API
     34  */
     35 public class PhoneNumberOfflineGeocoder {
     36   private static PhoneNumberOfflineGeocoder instance = null;
     37   private static final String MAPPING_DATA_DIRECTORY =
     38       "/com/android/i18n/phonenumbers/geocoding/data/";
     39   private PrefixFileReader prefixFileReader = null;
     40 
     41   private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
     42 
     43   // @VisibleForTesting
     44   PhoneNumberOfflineGeocoder(String phonePrefixDataDirectory) {
     45     prefixFileReader = new PrefixFileReader(phonePrefixDataDirectory);
     46   }
     47 
     48   /**
     49    * Gets a {@link PhoneNumberOfflineGeocoder} instance to carry out international phone number
     50    * geocoding.
     51    *
     52    * <p> The {@link PhoneNumberOfflineGeocoder} is implemented as a singleton. Therefore, calling
     53    * this method multiple times will only result in one instance being created.
     54    *
     55    * @return  a {@link PhoneNumberOfflineGeocoder} instance
     56    */
     57   @dalvik.annotation.compat.UnsupportedAppUsage
     58   public static synchronized PhoneNumberOfflineGeocoder getInstance() {
     59     if (instance == null) {
     60       instance = new PhoneNumberOfflineGeocoder(MAPPING_DATA_DIRECTORY);
     61     }
     62     return instance;
     63   }
     64 
     65   /**
     66    * Returns the customary display name in the given language for the given territory the phone
     67    * number is from. If it could be from many territories, nothing is returned.
     68    */
     69   private String getCountryNameForNumber(PhoneNumber number, Locale language) {
     70     List<String> regionCodes =
     71         phoneUtil.getRegionCodesForCountryCode(number.getCountryCode());
     72     if (regionCodes.size() == 1) {
     73       return getRegionDisplayName(regionCodes.get(0), language);
     74     } else {
     75       String regionWhereNumberIsValid = "ZZ";
     76       for (String regionCode : regionCodes) {
     77         if (phoneUtil.isValidNumberForRegion(number, regionCode)) {
     78           // If the number has already been found valid for one region, then we don't know which
     79           // region it belongs to so we return nothing.
     80           if (!regionWhereNumberIsValid.equals("ZZ")) {
     81             return "";
     82           }
     83           regionWhereNumberIsValid = regionCode;
     84         }
     85       }
     86       return getRegionDisplayName(regionWhereNumberIsValid, language);
     87     }
     88   }
     89 
     90   /**
     91    * Returns the customary display name in the given language for the given region.
     92    */
     93   private String getRegionDisplayName(String regionCode, Locale language) {
     94     return (regionCode == null || regionCode.equals("ZZ")
     95         || regionCode.equals(PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY))
     96         ? "" : new Locale("", regionCode).getDisplayCountry(language);
     97   }
     98 
     99   /**
    100    * Returns a text description for the given phone number, in the language provided. The
    101    * description might consist of the name of the country where the phone number is from, or the
    102    * name of the geographical area the phone number is from if more detailed information is
    103    * available.
    104    *
    105    * <p>This method assumes the validity of the number passed in has already been checked, and that
    106    * the number is suitable for geocoding. We consider fixed-line and mobile numbers possible
    107    * candidates for geocoding.
    108    *
    109    * @param number  a valid phone number for which we want to get a text description
    110    * @param languageCode  the language code for which the description should be written
    111    * @return  a text description for the given language code for the given phone number, or an
    112    *     empty string if the number could come from multiple countries, or the country code is
    113    *     in fact invalid
    114    */
    115   public String getDescriptionForValidNumber(PhoneNumber number, Locale languageCode) {
    116     String langStr = languageCode.getLanguage();
    117     String scriptStr = "";  // No script is specified
    118     String regionStr = languageCode.getCountry();
    119 
    120     String areaDescription;
    121     String mobileToken = PhoneNumberUtil.getCountryMobileToken(number.getCountryCode());
    122     String nationalNumber = phoneUtil.getNationalSignificantNumber(number);
    123     if (!mobileToken.equals("") && nationalNumber.startsWith(mobileToken)) {
    124       // In some countries, eg. Argentina, mobile numbers have a mobile token before the national
    125       // destination code, this should be removed before geocoding.
    126       nationalNumber = nationalNumber.substring(mobileToken.length());
    127       String region = phoneUtil.getRegionCodeForCountryCode(number.getCountryCode());
    128       PhoneNumber copiedNumber;
    129       try {
    130         copiedNumber = phoneUtil.parse(nationalNumber, region);
    131       } catch (NumberParseException e) {
    132         // If this happens, just reuse what we had.
    133         copiedNumber = number;
    134       }
    135       areaDescription = prefixFileReader.getDescriptionForNumber(copiedNumber, langStr, scriptStr,
    136                                                                  regionStr);
    137     } else {
    138       areaDescription = prefixFileReader.getDescriptionForNumber(number, langStr, scriptStr,
    139                                                                  regionStr);
    140     }
    141     return (areaDescription.length() > 0)
    142         ? areaDescription : getCountryNameForNumber(number, languageCode);
    143   }
    144 
    145   /**
    146    * As per {@link #getDescriptionForValidNumber(PhoneNumber, Locale)} but also considers the
    147    * region of the user. If the phone number is from the same region as the user, only a lower-level
    148    * description will be returned, if one exists. Otherwise, the phone number's region will be
    149    * returned, with optionally some more detailed information.
    150    *
    151    * <p>For example, for a user from the region "US" (United States), we would show "Mountain View,
    152    * CA" for a particular number, omitting the United States from the description. For a user from
    153    * the United Kingdom (region "GB"), for the same number we may show "Mountain View, CA, United
    154    * States" or even just "United States".
    155    *
    156    * <p>This method assumes the validity of the number passed in has already been checked.
    157    *
    158    * @param number  the phone number for which we want to get a text description
    159    * @param languageCode  the language code for which the description should be written
    160    * @param userRegion  the region code for a given user. This region will be omitted from the
    161    *     description if the phone number comes from this region. It should be a two-letter
    162    *     upper-case CLDR region code.
    163    * @return  a text description for the given language code for the given phone number, or an
    164    *     empty string if the number could come from multiple countries, or the country code is
    165    *     in fact invalid
    166    */
    167   public String getDescriptionForValidNumber(PhoneNumber number, Locale languageCode,
    168                                              String userRegion) {
    169     // If the user region matches the number's region, then we just show the lower-level
    170     // description, if one exists - if no description exists, we will show the region(country) name
    171     // for the number.
    172     String regionCode = phoneUtil.getRegionCodeForNumber(number);
    173     if (userRegion.equals(regionCode)) {
    174       return getDescriptionForValidNumber(number, languageCode);
    175     }
    176     // Otherwise, we just show the region(country) name for now.
    177     return getRegionDisplayName(regionCode, languageCode);
    178     // TODO: Concatenate the lower-level and country-name information in an appropriate
    179     // way for each language.
    180   }
    181 
    182   /**
    183    * As per {@link #getDescriptionForValidNumber(PhoneNumber, Locale)} but explicitly checks
    184    * the validity of the number passed in.
    185    *
    186    * @param number  the phone number for which we want to get a text description
    187    * @param languageCode  the language code for which the description should be written
    188    * @return  a text description for the given language code for the given phone number, or empty
    189    *     string if the number passed in is invalid or could belong to multiple countries
    190    */
    191   @dalvik.annotation.compat.UnsupportedAppUsage
    192   public String getDescriptionForNumber(PhoneNumber number, Locale languageCode) {
    193     PhoneNumberType numberType = phoneUtil.getNumberType(number);
    194     if (numberType == PhoneNumberType.UNKNOWN) {
    195       return "";
    196     } else if (!phoneUtil.isNumberGeographical(numberType, number.getCountryCode())) {
    197       return getCountryNameForNumber(number, languageCode);
    198     }
    199     return getDescriptionForValidNumber(number, languageCode);
    200   }
    201 
    202   /**
    203    * As per {@link #getDescriptionForValidNumber(PhoneNumber, Locale, String)} but
    204    * explicitly checks the validity of the number passed in.
    205    *
    206    * @param number  the phone number for which we want to get a text description
    207    * @param languageCode  the language code for which the description should be written
    208    * @param userRegion  the region code for a given user. This region will be omitted from the
    209    *     description if the phone number comes from this region. It should be a two-letter
    210    *     upper-case CLDR region code.
    211    * @return  a text description for the given language code for the given phone number, or empty
    212    *     string if the number passed in is invalid or could belong to multiple countries
    213    */
    214   public String getDescriptionForNumber(PhoneNumber number, Locale languageCode,
    215                                         String userRegion) {
    216     PhoneNumberType numberType = phoneUtil.getNumberType(number);
    217     if (numberType == PhoneNumberType.UNKNOWN) {
    218       return "";
    219     } else if (!phoneUtil.isNumberGeographical(numberType, number.getCountryCode())) {
    220       return getCountryNameForNumber(number, languageCode);
    221     }
    222     return getDescriptionForValidNumber(number, languageCode, userRegion);
    223   }
    224 }
    225