diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index a877c738b7268..13713e5e0a77a 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -26,8 +26,11 @@ import android.provider.ContactsContract; import android.text.Editable; import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.util.Log; import android.util.SparseIntArray; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING; + import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -57,6 +60,9 @@ public class PhoneNumberUtils public static final int TOA_International = 0x91; public static final int TOA_Unknown = 0x81; + static final String LOG_TAG = "PhoneNumberUtils"; + private static final boolean DBG = false; + /* * global-phone-number = ["+"] 1*( DIGIT / written-sep ) * written-sep = ("-"/".") @@ -227,6 +233,9 @@ public class PhoneNumberUtils } } + private static void log(String msg) { + Log.d(LOG_TAG, msg); + } /** index of the last character of the network portion * (eg anything after is a post-dial string) */ @@ -741,6 +750,14 @@ public class PhoneNumberUtils return true; } + private static boolean isNonSeparator(String address) { + for (int i = 0, count = address.length(); i < count; i++) { + if (!isNonSeparator(address.charAt(i))) { + return false; + } + } + return true; + } /** * Note: calls extractNetworkPortion(), so do not use for * SIM EF[ADN] style records @@ -1229,4 +1246,261 @@ public class PhoneNumberUtils KEYPAD_MAP.put('w', '9'); KEYPAD_MAP.put('x', '9'); KEYPAD_MAP.put('y', '9'); KEYPAD_MAP.put('z', '9'); KEYPAD_MAP.put('W', '9'); KEYPAD_MAP.put('X', '9'); KEYPAD_MAP.put('Y', '9'); KEYPAD_MAP.put('Z', '9'); } + + //================ Plus Code formatting ========================= + private static final char PLUS_SIGN_CHAR = '+'; + private static final String PLUS_SIGN_STRING = "+"; + private static final String NANP_IDP_STRING = "011"; + private static final int NANP_LENGTH = 10; + + /** + * This function checks if there is a plus sign (+) in the passed-in dialing number. + * If there is, it processes the plus sign based on the default telephone + * numbering plan of the system when the phone is activated and the current + * telephone numbering plan of the system that the phone is camped on. + * Currently, we only support the case that the default and current telephone + * numbering plans are North American Numbering Plan(NANP). + * + * The passed-in dialStr should only contain the valid format as described below, + * 1) the 1st character in the dialStr should be one of the really dialable + * characters listed below + * ISO-LATIN characters 0-9, *, # , + + * 2) the dialStr should already strip out the separator characters, + * every character in the dialStr should be one of the non separator characters + * listed below + * ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE + * + * Otherwise, this function returns the dial string passed in + * + * This API is for CDMA only + * + * @hide TODO: pending API Council approval + */ + public static String cdmaCheckAndProcessPlusCode(String dialStr) { + if (!TextUtils.isEmpty(dialStr)) { + if (isReallyDialable(dialStr.charAt(0)) && + isNonSeparator(dialStr)) { + return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr, + getFormatTypeForLocale(Locale.getDefault())); + } + } + return dialStr; + } + + /** + * This function should be called from checkAndProcessPlusCode only + * And it is used for test purpose also. + * + * It checks the dial string by looping through the network portion, + * post dial portion 1, post dial porting 2, etc. If there is any + * plus sign, then process the plus sign. + * Currently, this function supports the plus sign conversion within NANP only. + * Specifically, it handles the plus sign in the following ways: + * 1)+NANP or +1NANP,remove +, e.g. + * +8475797000 is converted to 8475797000, + * +18475797000 is converted to 18475797000, + * 2)+non-NANP Numbers,replace + with the current NANP IDP, e.g, + * +11875767800 is converted to 01111875767800 + * 3)+NANP in post dial string(s), e.g. + * 8475797000;+8475231753 is converted to 8475797000;8475231753 + * + * This function returns the original dial string if locale/numbering plan + * aren't supported. + * + * @hide + */ + public static String cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int numFormat) { + String retStr = dialStr; + + // Checks if the plus sign character is in the passed-in dial string + if (dialStr != null && + dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) { + + String postDialStr = null; + String tempDialStr = dialStr; + + // Sets the retStr to null since the conversion will be performed below. + retStr = null; + if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr); + // This routine is to process the plus sign in the dial string by loop through + // the network portion, post dial portion 1, post dial portion 2... etc. if + // applied + do { + String networkDialStr; + + // Format the string based on the rules for the country the number is from + if (numFormat != FORMAT_NANP) { + // TODO: to support NANP international conversion and + // other telephone numbering plan + // Currently the phone is ever used in non-NANP system + // return the original dial string + Log.e("checkAndProcessPlusCode:non-NANP not supported", dialStr); + return dialStr; + } else { + // For the case that the default and current telephone + // numbering plans are NANP + networkDialStr = extractNetworkPortion(tempDialStr); + // Handles the conversion within NANP + networkDialStr = processPlusCodeWithinNanp(networkDialStr); + } + // Concatenates the string that is converted from network portion + if (!TextUtils.isEmpty(networkDialStr)) { + if (retStr == null) { + retStr = networkDialStr; + } else { + retStr = retStr.concat(networkDialStr); + } + } else { + // This should never happen since we checked the if dialStr is null + // and if it contains the plus sign in the begining of this function. + // The plus sign is part of the network portion. + Log.e("checkAndProcessPlusCode: null newDialStr", networkDialStr); + return dialStr; + } + postDialStr = extractPostDialPortion(tempDialStr); + if (!TextUtils.isEmpty(postDialStr)) { + int dialableIndex = findDialableIndexFromPostDialStr(postDialStr); + + // dialableIndex should always be greater than 0 + if (dialableIndex >= 1) { + retStr = appendPwCharBackToOrigDialStr(dialableIndex, + retStr,postDialStr); + // Skips the P/W character, extracts the dialable portion + tempDialStr = postDialStr.substring(dialableIndex); + } else { + // Non-dialable character such as P/W should not be at the end of + // the dial string after P/W processing in CdmaConnection.java + // Set the postDialStr to "" to break out of the loop + if (dialableIndex < 0) { + postDialStr = ""; + } + Log.e("wrong postDialStr=", postDialStr); + } + } + if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr); + } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr)); + } + return retStr; + } + + // This function gets the default international dialing prefix + private static String getDefaultIdp( ) { + String ps = null; + SystemProperties.get(PROPERTY_IDP_STRING, ps); + if (TextUtils.isEmpty(ps)) { + ps = NANP_IDP_STRING; + } + return ps; + } + + private static boolean isTwoToNine (char c) { + if (c >= '2' && c <= '9') { + return true; + } else { + return false; + } + } + + /** + * This function checks if the passed in string conforms to the NANP format + * i.e. NXX-NXX-XXXX, N is any digit 2-9 and X is any digit 0-9 + */ + private static boolean isNanp (String dialStr) { + boolean retVal = false; + if (dialStr != null) { + if (dialStr.length() == NANP_LENGTH) { + if (isTwoToNine(dialStr.charAt(0)) && + isTwoToNine(dialStr.charAt(3))) { + retVal = true; + for (int i=1; i (currIndex + 1)) { + // If PW char sequence has more than 2 PW characters, + // skip to the last character since the sequence already be + // converted to WAIT character + if (nextIndex > (currIndex + 2)) { currIndex = nextIndex - 1; } } else if (nextIndex == length) { @@ -927,7 +916,7 @@ public class CdmaConnection extends Connection { } currIndex++; } - return ret.toString(); + return PhoneNumberUtils.cdmaCheckAndProcessPlusCode(ret.toString()); } private void log(String msg) { diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java index ff73b32d7f7b8..466b555e8f888 100644 --- a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java +++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -335,4 +335,73 @@ public class PhoneNumberUtilsTest extends TestCase { assertEquals("(800) 222-3334", PhoneNumberUtils.convertKeypadLettersToDigits("(800) ABC-DEFG")); } + + @SmallTest + public void testCheckAndProcessPlusCode() { + assertEquals("8475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000")); + assertEquals("18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+18475797000")); + assertEquals("0111234567", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+1234567")); + assertEquals("01123456700000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+23456700000")); + assertEquals("01111875767800", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+11875767800")); + assertEquals("8475797000,18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+18475231753")); + assertEquals("8475797000,18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000,+18475231753")); + assertEquals("8475797000;8475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;+8475231753")); + assertEquals("8475797000,0111234567", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+1234567")); + assertEquals("847597000;01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847597000;+11875767000")); + assertEquals("8475797000,,8475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,+8475231753")); + assertEquals("8475797000;,8475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+8475231753")); + assertEquals("8475797000,;18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+18475231753")); + assertEquals("8475797000;,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+11875767000")); + assertEquals("8475797000,;01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+11875767000")); + assertEquals("8475797000,,,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,,+11875767000")); + assertEquals("8475797000;,,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,,+11875767000")); + assertEquals("+;,8475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+;,8475797000")); + assertEquals("8475797000,", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,")); + assertEquals("847+579-7000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847+579-7000")); + assertEquals(",8475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode(",8475797000")); + assertEquals(";;8475797000,,", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode(";;8475797000,,")); + assertEquals("+this+is$weird;,+", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+this+is$weird;,+")); + assertEquals("", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("")); + assertNull(PhoneNumberUtils.cdmaCheckAndProcessPlusCode(null)); + } + + @SmallTest + public void testCheckAndProcessPlusCodeByNumberFormat() { + assertEquals("+8475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+8475797000", + PhoneNumberUtils.FORMAT_JAPAN)); + assertEquals("+0384756700", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+0384756700", + PhoneNumberUtils.FORMAT_JAPAN)); + assertEquals("+1234567", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+1234567", + PhoneNumberUtils.FORMAT_UNKNOWN)); + assertEquals("+23456700000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+23456700000", + PhoneNumberUtils.FORMAT_UNKNOWN)); + } }