diff options
Diffstat (limited to 'src/com/android/dialer/dialpad/SmartDialPrefix.java')
-rw-r--r-- | src/com/android/dialer/dialpad/SmartDialPrefix.java | 608 |
1 files changed, 0 insertions, 608 deletions
diff --git a/src/com/android/dialer/dialpad/SmartDialPrefix.java b/src/com/android/dialer/dialpad/SmartDialPrefix.java deleted file mode 100644 index a0b51ebb5..000000000 --- a/src/com/android/dialer/dialpad/SmartDialPrefix.java +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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.dialer.dialpad; - -import android.content.Context; - -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.telephony.TelephonyManager; -import android.text.TextUtils; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -/** - * Smart Dial utility class to find prefixes of contacts. It contains both methods to find supported - * prefix combinations for contact names, and also methods to find supported prefix combinations for - * contacts' phone numbers. Each contact name is separated into several tokens, such as first name, - * middle name, family name etc. Each phone number is also separated into country code, NANP area - * code, and local number if such separation is possible. - */ -public class SmartDialPrefix { - - /** The number of starting and ending tokens in a contact's name considered for initials. - * For example, if both constants are set to 2, and a contact's name is - * "Albert Ben Charles Daniel Ed Foster", the first two tokens "Albert" "Ben", and last two - * tokens "Ed" "Foster" can be replaced by their initials in contact name matching. - * Users can look up this contact by combinations of his initials such as "AF" "BF" "EF" "ABF" - * "BEF" "ABEF" etc, but can not use combinations such as "CF" "DF" "ACF" "ADF" etc. - */ - private static final int LAST_TOKENS_FOR_INITIALS = 2; - private static final int FIRST_TOKENS_FOR_INITIALS = 2; - - /** The country code of the user's sim card obtained by calling getSimCountryIso*/ - private static final String PREF_USER_SIM_COUNTRY_CODE = - "DialtactsActivity_user_sim_country_code"; - private static final String PREF_USER_SIM_COUNTRY_CODE_DEFAULT = null; - private static String sUserSimCountryCode = PREF_USER_SIM_COUNTRY_CODE_DEFAULT; - - /** Indicates whether user is in NANP regions.*/ - private static boolean sUserInNanpRegion = false; - - /** Set of country names that use NANP code.*/ - private static Set<String> sNanpCountries = null; - - /** Set of supported country codes in front of the phone number. */ - private static Set<String> sCountryCodes = null; - - /** Dialpad mapping. */ - private static final SmartDialMap mMap = new LatinSmartDialMap(); - - private static boolean sNanpInitialized = false; - - /** Initializes the Nanp settings, and finds out whether user is in a NANP region.*/ - public static void initializeNanpSettings(Context context){ - final TelephonyManager manager = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - if (manager != null) { - sUserSimCountryCode = manager.getSimCountryIso(); - } - - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - if (sUserSimCountryCode != null) { - /** Updates shared preferences with the latest country obtained from getSimCountryIso.*/ - prefs.edit().putString(PREF_USER_SIM_COUNTRY_CODE, sUserSimCountryCode).apply(); - } else { - /** Uses previously stored country code if loading fails. */ - sUserSimCountryCode = prefs.getString(PREF_USER_SIM_COUNTRY_CODE, - PREF_USER_SIM_COUNTRY_CODE_DEFAULT); - } - /** Queries the NANP country list to find out whether user is in a NANP region.*/ - sUserInNanpRegion = isCountryNanp(sUserSimCountryCode); - sNanpInitialized = true; - } - - /** - * Explicitly setting the user Nanp to the given boolean - */ - @VisibleForTesting - public static void setUserInNanpRegion(boolean userInNanpRegion) { - sUserInNanpRegion = userInNanpRegion; - } - - /** - * Class to record phone number parsing information. - */ - public static class PhoneNumberTokens { - /** Country code of the phone number. */ - final String countryCode; - - /** Offset of national number after the country code. */ - final int countryCodeOffset; - - /** Offset of local number after NANP area code.*/ - final int nanpCodeOffset; - - public PhoneNumberTokens(String countryCode, int countryCodeOffset, int nanpCodeOffset) { - this.countryCode = countryCode; - this.countryCodeOffset = countryCodeOffset; - this.nanpCodeOffset = nanpCodeOffset; - } - } - - /** - * Parses a contact's name into a list of separated tokens. - * - * @param contactName Contact's name stored in string. - * @return A list of name tokens, for example separated first names, last name, etc. - */ - public static ArrayList<String> parseToIndexTokens(String contactName) { - final int length = contactName.length(); - final ArrayList<String> result = Lists.newArrayList(); - char c; - final StringBuilder currentIndexToken = new StringBuilder(); - /** - * Iterates through the whole name string. If the current character is a valid character, - * append it to the current token. If the current character is not a valid character, for - * example space " ", mark the current token as complete and add it to the list of tokens. - */ - for (int i = 0; i < length; i++) { - c = mMap.normalizeCharacter(contactName.charAt(i)); - if (mMap.isValidDialpadCharacter(c)) { - /** Converts a character into the number on dialpad that represents the character.*/ - currentIndexToken.append(mMap.getDialpadIndex(c)); - } else { - if (currentIndexToken.length() != 0) { - result.add(currentIndexToken.toString()); - } - currentIndexToken.delete(0, currentIndexToken.length()); - } - } - - /** Adds the last token in case it has not been added.*/ - if (currentIndexToken.length() != 0) { - result.add(currentIndexToken.toString()); - } - return result; - } - - /** - * Generates a list of strings that any prefix of any string in the list can be used to look - * up the contact's name. - * - * @param index The contact's name in string. - * @return A List of strings, whose prefix can be used to look up the contact. - */ - public static ArrayList<String> generateNamePrefixes(String index) { - final ArrayList<String> result = Lists.newArrayList(); - - /** Parses the name into a list of tokens.*/ - final ArrayList<String> indexTokens = parseToIndexTokens(index); - - if (indexTokens.size() > 0) { - /** Adds the full token combinations to the list. For example, a contact with name - * "Albert Ben Ed Foster" can be looked up by any prefix of the following strings - * "Foster" "EdFoster" "BenEdFoster" and "AlbertBenEdFoster". This covers all cases of - * look up that contains only one token, and that spans multiple continuous tokens. - */ - final StringBuilder fullNameToken = new StringBuilder(); - for (int i = indexTokens.size() - 1; i >= 0; i--) { - fullNameToken.insert(0, indexTokens.get(i)); - result.add(fullNameToken.toString()); - } - - /** Adds initial combinations to the list, with the number of initials restricted by - * {@link #LAST_TOKENS_FOR_INITIALS} and {@link #FIRST_TOKENS_FOR_INITIALS}. - * For example, a contact with name "Albert Ben Ed Foster" can be looked up by any - * prefix of the following strings "EFoster" "BFoster" "BEFoster" "AFoster" "ABFoster" - * "AEFoster" and "ABEFoster". This covers all cases of initial lookup. - */ - ArrayList<String> fullNames = Lists.newArrayList(); - fullNames.add(indexTokens.get(indexTokens.size() - 1)); - final int recursiveNameStart = result.size(); - int recursiveNameEnd = result.size(); - String initial = ""; - for (int i = indexTokens.size() - 2; i >= 0; i--) { - if ((i >= indexTokens.size() - LAST_TOKENS_FOR_INITIALS) || - (i < FIRST_TOKENS_FOR_INITIALS)) { - initial = indexTokens.get(i).substring(0, 1); - - /** Recursively adds initial combinations to the list.*/ - for (int j = 0; j < fullNames.size(); ++j) { - result.add(initial + fullNames.get(j)); - } - for (int j = recursiveNameStart; j < recursiveNameEnd; ++j) { - result.add(initial + result.get(j)); - } - recursiveNameEnd = result.size(); - final String currentFullName = fullNames.get(fullNames.size() - 1); - fullNames.add(indexTokens.get(i) + currentFullName); - } - } - } - - return result; - } - - /** - * Computes a list of number strings based on tokens of a given phone number. Any prefix - * of any string in the list can be used to look up the phone number. The list include the - * full phone number, the national number if there is a country code in the phone number, and - * the local number if there is an area code in the phone number following the NANP format. - * For example, if a user has phone number +41 71 394 8392, the list will contain 41713948392 - * and 713948392. Any prefix to either of the strings can be used to look up the phone number. - * If a user has a phone number +1 555-302-3029 (NANP format), the list will contain - * 15553023029, 5553023029, and 3023029. - * - * @param number String of user's phone number. - * @return A list of strings where any prefix of any entry can be used to look up the number. - */ - public static ArrayList<String> parseToNumberTokens(String number) { - final ArrayList<String> result = Lists.newArrayList(); - if (!TextUtils.isEmpty(number)) { - /** Adds the full number to the list.*/ - result.add(SmartDialNameMatcher.normalizeNumber(number, mMap)); - - final PhoneNumberTokens phoneNumberTokens = parsePhoneNumber(number); - if (phoneNumberTokens == null) { - return result; - } - - if (phoneNumberTokens.countryCodeOffset != 0) { - result.add(SmartDialNameMatcher.normalizeNumber(number, - phoneNumberTokens.countryCodeOffset, mMap)); - } - - if (phoneNumberTokens.nanpCodeOffset != 0) { - result.add(SmartDialNameMatcher.normalizeNumber(number, - phoneNumberTokens.nanpCodeOffset, mMap)); - } - } - return result; - } - - /** - * Parses a phone number to find out whether it has country code and NANP area code. - * - * @param number Raw phone number. - * @return a PhoneNumberToken instance with country code, NANP code information. - */ - public static PhoneNumberTokens parsePhoneNumber(String number) { - String countryCode = ""; - int countryCodeOffset = 0; - int nanpNumberOffset = 0; - - if (!TextUtils.isEmpty(number)) { - String normalizedNumber = SmartDialNameMatcher.normalizeNumber(number, mMap); - if (number.charAt(0) == '+') { - /** If the number starts with '+', tries to find valid country code. */ - for (int i = 1; i <= 1 + 3; i++) { - if (number.length() <= i) { - break; - } - countryCode = number.substring(1, i); - if (isValidCountryCode(countryCode)) { - countryCodeOffset = i; - break; - } - } - } else { - /** If the number does not start with '+', finds out whether it is in NANP - * format and has '1' preceding the number. - */ - if ((normalizedNumber.length() == 11) && (normalizedNumber.charAt(0) == '1') && - (sUserInNanpRegion)) { - countryCode = "1"; - countryCodeOffset = number.indexOf(normalizedNumber.charAt(1)); - if (countryCodeOffset == -1) { - countryCodeOffset = 0; - } - } - } - - /** If user is in NANP region, finds out whether a number is in NANP format.*/ - if (sUserInNanpRegion) { - String areaCode = ""; - if (countryCode.equals("") && normalizedNumber.length() == 10){ - /** if the number has no country code but fits the NANP format, extracts the - * NANP area code, and finds out offset of the local number. - */ - areaCode = normalizedNumber.substring(0, 3); - } else if (countryCode.equals("1") && normalizedNumber.length() == 11) { - /** If the number has country code '1', finds out area code and offset of the - * local number. - */ - areaCode = normalizedNumber.substring(1, 4); - } - if (!areaCode.equals("")) { - final int areaCodeIndex = number.indexOf(areaCode); - if (areaCodeIndex != -1) { - nanpNumberOffset = number.indexOf(areaCode) + 3; - } - } - } - } - return new PhoneNumberTokens(countryCode, countryCodeOffset, nanpNumberOffset); - } - - /** - * Checkes whether a country code is valid. - */ - private static boolean isValidCountryCode(String countryCode) { - if (sCountryCodes == null) { - sCountryCodes = initCountryCodes(); - } - return sCountryCodes.contains(countryCode); - } - - private static Set<String> initCountryCodes() { - final HashSet<String> result = new HashSet<String>(); - result.add("1"); - result.add("7"); - result.add("20"); - result.add("27"); - result.add("30"); - result.add("31"); - result.add("32"); - result.add("33"); - result.add("34"); - result.add("36"); - result.add("39"); - result.add("40"); - result.add("41"); - result.add("43"); - result.add("44"); - result.add("45"); - result.add("46"); - result.add("47"); - result.add("48"); - result.add("49"); - result.add("51"); - result.add("52"); - result.add("53"); - result.add("54"); - result.add("55"); - result.add("56"); - result.add("57"); - result.add("58"); - result.add("60"); - result.add("61"); - result.add("62"); - result.add("63"); - result.add("64"); - result.add("65"); - result.add("66"); - result.add("81"); - result.add("82"); - result.add("84"); - result.add("86"); - result.add("90"); - result.add("91"); - result.add("92"); - result.add("93"); - result.add("94"); - result.add("95"); - result.add("98"); - result.add("211"); - result.add("212"); - result.add("213"); - result.add("216"); - result.add("218"); - result.add("220"); - result.add("221"); - result.add("222"); - result.add("223"); - result.add("224"); - result.add("225"); - result.add("226"); - result.add("227"); - result.add("228"); - result.add("229"); - result.add("230"); - result.add("231"); - result.add("232"); - result.add("233"); - result.add("234"); - result.add("235"); - result.add("236"); - result.add("237"); - result.add("238"); - result.add("239"); - result.add("240"); - result.add("241"); - result.add("242"); - result.add("243"); - result.add("244"); - result.add("245"); - result.add("246"); - result.add("247"); - result.add("248"); - result.add("249"); - result.add("250"); - result.add("251"); - result.add("252"); - result.add("253"); - result.add("254"); - result.add("255"); - result.add("256"); - result.add("257"); - result.add("258"); - result.add("260"); - result.add("261"); - result.add("262"); - result.add("263"); - result.add("264"); - result.add("265"); - result.add("266"); - result.add("267"); - result.add("268"); - result.add("269"); - result.add("290"); - result.add("291"); - result.add("297"); - result.add("298"); - result.add("299"); - result.add("350"); - result.add("351"); - result.add("352"); - result.add("353"); - result.add("354"); - result.add("355"); - result.add("356"); - result.add("357"); - result.add("358"); - result.add("359"); - result.add("370"); - result.add("371"); - result.add("372"); - result.add("373"); - result.add("374"); - result.add("375"); - result.add("376"); - result.add("377"); - result.add("378"); - result.add("379"); - result.add("380"); - result.add("381"); - result.add("382"); - result.add("385"); - result.add("386"); - result.add("387"); - result.add("389"); - result.add("420"); - result.add("421"); - result.add("423"); - result.add("500"); - result.add("501"); - result.add("502"); - result.add("503"); - result.add("504"); - result.add("505"); - result.add("506"); - result.add("507"); - result.add("508"); - result.add("509"); - result.add("590"); - result.add("591"); - result.add("592"); - result.add("593"); - result.add("594"); - result.add("595"); - result.add("596"); - result.add("597"); - result.add("598"); - result.add("599"); - result.add("670"); - result.add("672"); - result.add("673"); - result.add("674"); - result.add("675"); - result.add("676"); - result.add("677"); - result.add("678"); - result.add("679"); - result.add("680"); - result.add("681"); - result.add("682"); - result.add("683"); - result.add("685"); - result.add("686"); - result.add("687"); - result.add("688"); - result.add("689"); - result.add("690"); - result.add("691"); - result.add("692"); - result.add("800"); - result.add("808"); - result.add("850"); - result.add("852"); - result.add("853"); - result.add("855"); - result.add("856"); - result.add("870"); - result.add("878"); - result.add("880"); - result.add("881"); - result.add("882"); - result.add("883"); - result.add("886"); - result.add("888"); - result.add("960"); - result.add("961"); - result.add("962"); - result.add("963"); - result.add("964"); - result.add("965"); - result.add("966"); - result.add("967"); - result.add("968"); - result.add("970"); - result.add("971"); - result.add("972"); - result.add("973"); - result.add("974"); - result.add("975"); - result.add("976"); - result.add("977"); - result.add("979"); - result.add("992"); - result.add("993"); - result.add("994"); - result.add("995"); - result.add("996"); - result.add("998"); - return result; - } - - public static SmartDialMap getMap() { - return mMap; - } - - /** - * Indicates whether the given country uses NANP numbers - * @see <a href="https://en.wikipedia.org/wiki/North_American_Numbering_Plan"> - * https://en.wikipedia.org/wiki/North_American_Numbering_Plan</a> - * - * @param country ISO 3166 country code (case doesn't matter) - * @return True if country uses NANP numbers (e.g. US, Canada), false otherwise - */ - @VisibleForTesting - public static boolean isCountryNanp(String country) { - if (TextUtils.isEmpty(country)) { - return false; - } - if (sNanpCountries == null) { - sNanpCountries = initNanpCountries(); - } - return sNanpCountries.contains(country.toUpperCase()); - } - - private static Set<String> initNanpCountries() { - final HashSet<String> result = new HashSet<String>(); - result.add("US"); // United States - result.add("CA"); // Canada - result.add("AS"); // American Samoa - result.add("AI"); // Anguilla - result.add("AG"); // Antigua and Barbuda - result.add("BS"); // Bahamas - result.add("BB"); // Barbados - result.add("BM"); // Bermuda - result.add("VG"); // British Virgin Islands - result.add("KY"); // Cayman Islands - result.add("DM"); // Dominica - result.add("DO"); // Dominican Republic - result.add("GD"); // Grenada - result.add("GU"); // Guam - result.add("JM"); // Jamaica - result.add("PR"); // Puerto Rico - result.add("MS"); // Montserrat - result.add("MP"); // Northern Mariana Islands - result.add("KN"); // Saint Kitts and Nevis - result.add("LC"); // Saint Lucia - result.add("VC"); // Saint Vincent and the Grenadines - result.add("TT"); // Trinidad and Tobago - result.add("TC"); // Turks and Caicos Islands - result.add("VI"); // U.S. Virgin Islands - return result; - } - - /** - * Returns whether the user is in a region that uses Nanp format based on the sim location. - * - * @return Whether user is in Nanp region. - */ - public static boolean getUserInNanpRegion() { - return sUserInNanpRegion; - } -} |