Merge change 8331
* changes: added non-numeric cdma sms address support
This commit is contained in:
@@ -584,38 +584,6 @@ public class SmsMessage extends SmsMessageBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static CdmaSmsAddress parseCdmaSmsAddr(String addrStr) {
|
||||
// see C.S0015-B, v2.0, 3.4.3.3
|
||||
CdmaSmsAddress addr = new CdmaSmsAddress();
|
||||
addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF;
|
||||
try {
|
||||
addr.origBytes = addrStr.getBytes("UTF-8");
|
||||
for (int index = 0; index < addr.origBytes.length; index++) {
|
||||
if (addr.origBytes[index] >= '0' && addr.origBytes[index] <= '9') {
|
||||
if (addr.origBytes[index] == '0') {
|
||||
addr.origBytes[index] = 10;
|
||||
} else {
|
||||
addr.origBytes[index] -= '0';
|
||||
}
|
||||
} else if (addr.origBytes[index] == '*') {
|
||||
addr.origBytes[index] = 11;
|
||||
} else if (addr.origBytes[index] == '#') {
|
||||
addr.origBytes[index] = 12;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch (java.io.UnsupportedEncodingException ex) {
|
||||
Log.e(LOG_TAG, "CDMA address parsing failed: " + ex);
|
||||
return null;
|
||||
}
|
||||
addr.numberOfDigits = (byte)addr.origBytes.length;
|
||||
addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK;
|
||||
addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY;
|
||||
addr.ton = CdmaSmsAddress.TON_UNKNOWN;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the nextMessageId to a random value between 0 and 65536
|
||||
* See C.S0015-B, v2.0, 4.3.1.5
|
||||
@@ -642,7 +610,13 @@ public class SmsMessage extends SmsMessageBase {
|
||||
* TODO(cleanup): give this function a more meaningful name.
|
||||
*/
|
||||
|
||||
CdmaSmsAddress destAddr = parseCdmaSmsAddr(destAddrStr);
|
||||
/**
|
||||
* TODO(cleanup): Make returning null from the getSubmitPdu
|
||||
* variations meaningful -- clean up the error feedback
|
||||
* mechanism, and avoid null pointer exceptions.
|
||||
*/
|
||||
|
||||
CdmaSmsAddress destAddr = CdmaSmsAddress.parse(destAddrStr);
|
||||
if (destAddr == null) return null;
|
||||
|
||||
BearerData bearerData = new BearerData();
|
||||
|
||||
@@ -624,6 +624,12 @@ public final class BearerData {
|
||||
return rawData;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(cleanup): CdmaSmsAddress encoding should make use of
|
||||
* CdmaSmsAddress.parse provided that DTMF encoding is unified,
|
||||
* and the difference in 4bit vs 8bit is resolved.
|
||||
*/
|
||||
|
||||
private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
|
||||
if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
|
||||
try {
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.android.internal.telephony.cdma.sms;
|
||||
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import com.android.internal.telephony.SmsAddress;
|
||||
import com.android.internal.telephony.cdma.sms.UserData;
|
||||
import com.android.internal.util.HexDump;
|
||||
|
||||
public class CdmaSmsAddress extends SmsAddress {
|
||||
@@ -43,7 +46,8 @@ public class CdmaSmsAddress extends SmsAddress {
|
||||
|
||||
/**
|
||||
* Number Types for data networks.
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
|
||||
* (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table)
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset)
|
||||
* NOTE: value is stored in the parent class ton field.
|
||||
*/
|
||||
static public final int TON_UNKNOWN = 0x00;
|
||||
@@ -98,10 +102,127 @@ public class CdmaSmsAddress extends SmsAddress {
|
||||
builder.append(", numberPlan=" + numberPlan);
|
||||
builder.append(", numberOfDigits=" + numberOfDigits);
|
||||
builder.append(", ton=" + ton);
|
||||
builder.append(", address=" + address);
|
||||
builder.append(", address=\"" + address + "\"");
|
||||
builder.append(", origBytes=" + HexDump.toHexString(origBytes));
|
||||
builder.append(" }");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(cleanup): Refactor the parsing for addresses to better
|
||||
* share code and logic with GSM. Also, gather all DTMF/BCD
|
||||
* processing code in one place.
|
||||
*/
|
||||
|
||||
private static byte[] parseToDtmf(String address) {
|
||||
int digits = address.length();
|
||||
byte[] result = new byte[digits];
|
||||
for (int i = 0; i < digits; i++) {
|
||||
char c = address.charAt(i);
|
||||
int val = 0;
|
||||
if ((c >= '1') && (c <= '9')) val = c - '0';
|
||||
else if (c == '0') val = 10;
|
||||
else if (c == '*') val = 11;
|
||||
else if (c == '#') val = 12;
|
||||
else return null;
|
||||
result[i] = (byte)val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final char[] numericCharsDialable = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#'
|
||||
};
|
||||
|
||||
private static final char[] numericCharsSugar = {
|
||||
'(', ')', ' ', '-', '+'
|
||||
};
|
||||
|
||||
private static final SparseBooleanArray numericCharDialableMap = new SparseBooleanArray (
|
||||
numericCharsDialable.length + numericCharsSugar.length);
|
||||
static {
|
||||
for (int i = 0; i < numericCharsDialable.length; i++) {
|
||||
numericCharDialableMap.put(numericCharsDialable[i], true);
|
||||
}
|
||||
for (int i = 0; i < numericCharsSugar.length; i++) {
|
||||
numericCharDialableMap.put(numericCharsSugar[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a numeric address string, return the string without
|
||||
* syntactic sugar, meaning parens, spaces, hyphens/minuses, or
|
||||
* plus signs. If the input string contains non-numeric
|
||||
* non-punctuation characters, return null.
|
||||
*/
|
||||
private static String filterNumericSugar(String address) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int len = address.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = address.charAt(i);
|
||||
int mapIndex = numericCharDialableMap.indexOfKey(c);
|
||||
if (mapIndex < 0) return null;
|
||||
if (! numericCharDialableMap.valueAt(mapIndex)) continue;
|
||||
builder.append(c);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a string, return the string without whitespace,
|
||||
* including CR/LF.
|
||||
*/
|
||||
private static String filterWhitespace(String address) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int len = address.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = address.charAt(i);
|
||||
if ((c == ' ') || (c == '\r') || (c == '\n') || (c == '\t')) continue;
|
||||
builder.append(c);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a string, create a corresponding CdmaSmsAddress object.
|
||||
*
|
||||
* The result will be null if the input string is not
|
||||
* representable using printable ASCII.
|
||||
*
|
||||
* For numeric addresses, the string is cleaned up by removing
|
||||
* common punctuation. For alpha addresses, the string is cleaned
|
||||
* up by removing whitespace.
|
||||
*/
|
||||
public static CdmaSmsAddress parse(String address) {
|
||||
CdmaSmsAddress addr = new CdmaSmsAddress();
|
||||
addr.address = address;
|
||||
addr.ton = CdmaSmsAddress.TON_UNKNOWN;
|
||||
byte[] origBytes = null;
|
||||
String filteredAddr = filterNumericSugar(address);
|
||||
if (filteredAddr != null) {
|
||||
origBytes = parseToDtmf(filteredAddr);
|
||||
}
|
||||
if (origBytes != null) {
|
||||
addr.digitMode = DIGIT_MODE_4BIT_DTMF;
|
||||
addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
|
||||
if (address.indexOf('+') != -1) {
|
||||
addr.ton = TON_INTERNATIONAL_OR_IP;
|
||||
}
|
||||
} else {
|
||||
filteredAddr = filterWhitespace(address);
|
||||
origBytes = UserData.stringToAscii(filteredAddr);
|
||||
if (origBytes == null) {
|
||||
return null;
|
||||
}
|
||||
addr.digitMode = DIGIT_MODE_8BIT_CHAR;
|
||||
addr.numberMode = NUMBER_MODE_DATA_NETWORK;
|
||||
if (address.indexOf('@') != -1) {
|
||||
addr.ton = TON_NATIONAL_OR_EMAIL;
|
||||
}
|
||||
}
|
||||
addr.origBytes = origBytes;
|
||||
addr.numberOfDigits = origBytes.length;
|
||||
return addr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -92,6 +92,26 @@ public class UserData {
|
||||
charToAscii.put('\n', ASCII_CR_INDEX);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(cleanup): Move this very generic functionality somewhere
|
||||
* more general.
|
||||
*/
|
||||
/**
|
||||
* Given a string generate a corresponding ASCII-encoded byte
|
||||
* array, but limited to printable characters. If the input
|
||||
* contains unprintable characters, return null.
|
||||
*/
|
||||
public static byte[] stringToAscii(String str) {
|
||||
int len = str.length();
|
||||
byte[] result = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
int charCode = charToAscii.get(str.charAt(i), -1);
|
||||
if (charCode == -1) return null;
|
||||
result[i] = (byte)charCode;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping for IA5 values less than 32 are flow control signals
|
||||
* and not used here.
|
||||
|
||||
@@ -37,6 +37,67 @@ import android.util.Log;
|
||||
public class CdmaSmsTest extends AndroidTestCase {
|
||||
private final static String LOG_TAG = "CDMA";
|
||||
|
||||
@SmallTest
|
||||
public void testCdmaSmsAddrParsing() throws Exception {
|
||||
CdmaSmsAddress addr = CdmaSmsAddress.parse("6502531000");
|
||||
assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
|
||||
assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
|
||||
assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
|
||||
assertEquals(addr.numberOfDigits, 10);
|
||||
assertEquals(addr.origBytes.length, 10);
|
||||
byte[] data = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
assertEquals(addr.origBytes[i], data[i]);
|
||||
}
|
||||
addr = CdmaSmsAddress.parse("(650) 253-1000");
|
||||
assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
|
||||
assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
|
||||
assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
|
||||
assertEquals(addr.numberOfDigits, 10);
|
||||
assertEquals(addr.origBytes.length, 10);
|
||||
byte[] data2 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
|
||||
for (int i = 0; i < data2.length; i++) {
|
||||
assertEquals(addr.origBytes[i], data2[i]);
|
||||
}
|
||||
addr = CdmaSmsAddress.parse("(+886) 917 222 555");
|
||||
assertEquals(addr.ton, CdmaSmsAddress.TON_INTERNATIONAL_OR_IP);
|
||||
assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
|
||||
assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
|
||||
assertEquals(addr.numberOfDigits, 12);
|
||||
assertEquals(addr.origBytes.length, 12);
|
||||
byte[] data3 = {8, 8, 6, 9, 1, 7, 2, 2, 2, 5, 5, 5};
|
||||
for (int i = 0; i < data3.length; i++) {
|
||||
assertEquals(addr.origBytes[i], data3[i]);
|
||||
}
|
||||
addr = CdmaSmsAddress.parse("(650) *253-1000 #600");
|
||||
byte[] data4 = {6, 5, 10, 11, 2, 5, 3, 1, 10, 10, 10, 12, 6, 10, 10};
|
||||
for (int i = 0; i < data4.length; i++) {
|
||||
assertEquals(addr.origBytes[i], data4[i]);
|
||||
}
|
||||
String input = "x@y.com,a@b.com";
|
||||
addr = CdmaSmsAddress.parse(input);
|
||||
assertEquals(addr.ton, CdmaSmsAddress.TON_NATIONAL_OR_EMAIL);
|
||||
assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR);
|
||||
assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK);
|
||||
assertEquals(addr.numberOfDigits, 15);
|
||||
assertEquals(addr.origBytes.length, 15);
|
||||
assertEquals(new String(addr.origBytes), input);
|
||||
addr = CdmaSmsAddress.parse("foo bar");
|
||||
assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
|
||||
assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR);
|
||||
assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK);
|
||||
assertEquals(addr.numberOfDigits, 6);
|
||||
assertEquals(addr.origBytes.length, 6);
|
||||
assertEquals(new String(addr.origBytes), "foobar");
|
||||
addr = CdmaSmsAddress.parse("f\noo\tb a\rr");
|
||||
assertEquals(new String(addr.origBytes), "foobar");
|
||||
assertEquals(CdmaSmsAddress.parse("f\u0000oo bar"), null);
|
||||
assertEquals(CdmaSmsAddress.parse("f\u0007oo bar"), null);
|
||||
assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null);
|
||||
assertEquals(CdmaSmsAddress.parse("f\u1ECFboo\u001fbar"), null);
|
||||
assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testUserData7bitGsm() throws Exception {
|
||||
String pdu = "00031040900112488ea794e074d69e1b7392c270326cde9e98";
|
||||
|
||||
Reference in New Issue
Block a user