Merge change 21006

* changes:
  Fix the issue of incorrect conversion of the plus sign in a dial string.
This commit is contained in:
Android (Google) Code Review
2009-08-12 15:48:31 -07:00
3 changed files with 356 additions and 24 deletions

View File

@@ -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<NANP_LENGTH; i++ ) {
char c=dialStr.charAt(i);
if (!PhoneNumberUtils.isISODigit(c)) {
retVal = false;
break;
}
}
}
}
} else {
Log.e("isNanp: null dialStr passed in", dialStr);
}
return retVal;
}
/**
* This function checks if the passed in string conforms to 1-NANP format
*/
private static boolean isOneNanp(String dialStr) {
boolean retVal = false;
if (dialStr != null) {
String newDialStr = dialStr.substring(1);
if ((dialStr.charAt(0) == '1') && isNanp(newDialStr)) {
retVal = true;
}
} else {
Log.e("isOneNanp: null dialStr passed in", dialStr);
}
return retVal;
}
/**
* This function handles the plus code conversion within NANP CDMA network
* If the number format is
* 1)+NANP or +1NANP,remove +,
* 2)+non-NANP Numbers,replace + with the current IDP
*/
private static String processPlusCodeWithinNanp(String networkDialStr) {
String retStr = networkDialStr;
if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr);
// If there is a plus sign at the beginning of the dial string,
// Convert the plus sign to the default IDP since it's an international number
if (networkDialStr != null &
networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
networkDialStr.length() > 1) {
String newStr = networkDialStr.substring(1);
if (isNanp(newStr) || isOneNanp(newStr)) {
// Remove the leading plus sign
retStr = newStr;
} else {
String idpStr = getDefaultIdp();
// Replaces the plus sign with the default IDP
retStr = networkDialStr.replaceFirst("[+]", idpStr);
}
}
if (DBG) log("processPlusCodeWithinNanp,retStr=" + retStr);
return retStr;
}
// This function finds the index of the dialable character(s)
// in the post dial string
private static int findDialableIndexFromPostDialStr(String postDialStr) {
for (int index = 0;index < postDialStr.length();index++) {
char c = postDialStr.charAt(index);
if (isReallyDialable(c)) {
return index;
}
}
return -1;
}
// This function appends the non-diablable P/W character to the original
// dial string based on the dialable index passed in
private static String
appendPwCharBackToOrigDialStr(int dialableIndex,String origStr, String dialStr) {
String retStr;
// There is only 1 P/W character before the dialable characters
if (dialableIndex == 1) {
StringBuilder ret = new StringBuilder(origStr);
ret = ret.append(dialStr.charAt(0));
retStr = ret.toString();
} else {
// It means more than 1 P/W characters in the post dial string,
// appends to retStr
String nonDigitStr = dialStr.substring(0,dialableIndex);
retStr = origStr.concat(nonDigitStr);
}
return retStr;
}
}

View File

@@ -818,15 +818,12 @@ public class CdmaConnection extends Connection {
return c == PhoneNumberUtils.WAIT;
}
// This function is to find the next PAUSE character index if
// multiple pauses in a row. Otherwise it finds the next non PAUSE or
// non WAIT character index.
private static int
findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) {
boolean wMatched = false;
boolean wMatched = isWait(phoneNumber.charAt(currIndex));
int index = currIndex + 1;
int length = phoneNumber.length();
while (index < length) {
@@ -863,17 +860,17 @@ public class CdmaConnection extends Connection {
// Append the PW char
ret = (isPause(c)) ? PhoneNumberUtils.PAUSE : PhoneNumberUtils.WAIT;
// if there is a PAUSE in at the begining of PW character sequences, and this
// PW character sequences has more than 2 PAUSE and WAIT Characters,skip P, append W
if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 1))) {
// if there is a PAUSE in at the beginning of PW character sequences, and this
// PW character sequences has more than 2 PAUSE and WAIT Characters,skip PAUSE,
// append WAIT.
if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 2))) {
ret = PhoneNumberUtils.WAIT;
}
return ret;
}
/**
* format orignal dial string
* format original dial string
* 1) convert international dialing prefix "+" to
* string specified per region
*
@@ -892,20 +889,10 @@ public class CdmaConnection extends Connection {
StringBuilder ret = new StringBuilder();
char c;
int currIndex = 0;
while (currIndex < length) {
c = phoneNumber.charAt(currIndex);
if (PhoneNumberUtils.isDialable(c)) {
if (c == '+') {
String ps = null;
SystemProperties.get(TelephonyProperties.PROPERTY_IDP_STRING, ps);
if (TextUtils.isEmpty(ps)) {
ps = "011";
}
ret.append(ps);
} else {
ret.append(c);
}
} else if (isPause(c) || isWait(c)) {
if (isPause(c) || isWait(c)) {
if (currIndex < length - 1) {
// if PW not at the end
int nextIndex = findNextPCharOrNonPOrNonWCharIndex(phoneNumber, currIndex);
@@ -913,8 +900,10 @@ public class CdmaConnection extends Connection {
if (nextIndex < length) {
char pC = findPOrWCharToAppend(phoneNumber, currIndex, nextIndex);
ret.append(pC);
// If PW char is immediately followed by non-PW char
if (nextIndex > (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) {

View File

@@ -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));
}
}