summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--[-rwxr-xr-x]src/java/com/android/internal/telephony/cdma/sms/BearerData.java49
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java89
2 files changed, 94 insertions, 44 deletions
diff --git a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java b/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 7ff9e50..d40242c 100755..100644
--- a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -18,7 +18,6 @@ package com.android.internal.telephony.cdma.sms;
import android.content.res.Resources;
import android.telephony.SmsCbCmasInfo;
-import android.telephony.SmsCbMessage;
import android.telephony.cdma.CdmaSmsCbProgramData;
import android.telephony.cdma.CdmaSmsCbProgramResults;
import android.text.format.Time;
@@ -592,7 +591,6 @@ public final class BearerData {
byte[] payload = encodeUtf16(uData.payloadStr);
int udhBytes = udhData.length + 1; // Add length octet.
int udhCodeUnits = (udhBytes + 1) / 2;
- int udhPadding = udhBytes % 2;
int payloadCodeUnits = payload.length / 2;
uData.msgEncoding = UserData.ENCODING_UNICODE_16;
uData.msgEncodingSet = true;
@@ -600,7 +598,7 @@ public final class BearerData {
uData.payload = new byte[uData.numFields * 2];
uData.payload[0] = (byte)udhData.length;
System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
- System.arraycopy(payload, 0, uData.payload, udhBytes + udhPadding, payload.length);
+ System.arraycopy(payload, 0, uData.payload, udhBytes, payload.length);
}
private static void encodeEmsUserDataPayload(UserData uData)
@@ -994,27 +992,37 @@ public final class BearerData {
private static String decodeUtf8(byte[] data, int offset, int numFields)
throws CodingException
{
- if (numFields < 0 || (numFields + offset) > data.length) {
- throw new CodingException("UTF-8 decode failed: offset or length out of range");
- }
- try {
- return new String(data, offset, numFields, "UTF-8");
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("UTF-8 decode failed: " + ex);
- }
+ return decodeCharset(data, offset, numFields, 1, "UTF-8");
}
private static String decodeUtf16(byte[] data, int offset, int numFields)
throws CodingException
{
- int byteCount = numFields * 2;
- if (byteCount < 0 || (byteCount + offset) > data.length) {
- throw new CodingException("UTF-16 decode failed: offset or length out of range");
+ // Subtract header and possible padding byte (at end) from num fields.
+ int padding = offset % 2;
+ numFields -= (offset + padding) / 2;
+ return decodeCharset(data, offset, numFields, 2, "utf-16be");
+ }
+
+ private static String decodeCharset(byte[] data, int offset, int numFields, int width,
+ String charset) throws CodingException
+ {
+ if (numFields < 0 || (numFields * width + offset) > data.length) {
+ // Try to decode the max number of characters in payload
+ int padding = offset % width;
+ int maxNumFields = (data.length - offset - padding) / width;
+ if (maxNumFields < 0) {
+ throw new CodingException(charset + " decode failed: offset out of range");
+ }
+ Log.e(LOG_TAG, charset + " decode error: offset = " + offset + " numFields = "
+ + numFields + " data.length = " + data.length + " maxNumFields = "
+ + maxNumFields);
+ numFields = maxNumFields;
}
try {
- return new String(data, offset, byteCount, "utf-16be");
+ return new String(data, offset, numFields * width, charset);
} catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("UTF-16 decode failed: " + ex);
+ throw new CodingException(charset + " decode failed: " + ex);
}
}
@@ -1070,14 +1078,7 @@ public final class BearerData {
private static String decodeLatin(byte[] data, int offset, int numFields)
throws CodingException
{
- if (numFields < 0 || (numFields + offset) > data.length) {
- throw new CodingException("ISO-8859-1 decode failed: offset or length out of range");
- }
- try {
- return new String(data, offset, numFields, "ISO-8859-1");
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("ISO-8859-1 decode failed: " + ex);
- }
+ return decodeCharset(data, offset, numFields, 1, "ISO-8859-1");
}
private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java
index bb37b65..850babe 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java
@@ -17,27 +17,28 @@
package com.android.internal.telephony.cdma.sms;
import android.telephony.TelephonyManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
-import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.cdma.SmsMessage;
-import com.android.internal.telephony.cdma.sms.BearerData;
-import com.android.internal.telephony.cdma.sms.UserData;
-import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.util.BitwiseInputStream;
-import com.android.internal.util.BitwiseOutputStream;
import com.android.internal.util.HexDump;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import android.util.Log;
-
import java.util.ArrayList;
+import java.util.Arrays;
public class CdmaSmsTest extends AndroidTestCase {
- private final static String LOG_TAG = "XXX CdmaSmsTest XXX";
+
+ // CJK ideographs, Hiragana, Katakana, full width letters, Cyrillic, etc.
+ private static final String sUnicodeChars = "\u4e00\u4e01\u4e02\u4e03" +
+ "\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09\u4e0a\u4e0b\u4e0c\u4e0d" +
+ "\u4e0e\u4e0f\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048" +
+ "\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8" +
+ "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18" +
+ "\uff70\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78" +
+ "\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408" +
+ "\u00a2\u00a9\u00ae\u2122";
@SmallTest
public void testCdmaSmsAddrParsing() throws Exception {
@@ -811,23 +812,51 @@ public class CdmaSmsTest extends AndroidTestCase {
@SmallTest
public void testUserDataHeaderWithEightCharMsg() throws Exception {
+ encodeDecodeAssertEquals("01234567", 2, 2, false);
+ }
+
+ private void encodeDecodeAssertEquals(String payload, int index, int total,
+ boolean oddLengthHeader) throws Exception {
BearerData bearerData = new BearerData();
bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
bearerData.messageId = 55;
- SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
- concatRef.refNumber = 0xEE;
- concatRef.msgCount = 2;
- concatRef.seqNumber = 2;
- concatRef.isEightBits = true;
SmsHeader smsHeader = new SmsHeader();
- smsHeader.concatRef = concatRef;
+ if (oddLengthHeader) {
+ // Odd length header to verify correct UTF-16 header padding
+ SmsHeader.MiscElt miscElt = new SmsHeader.MiscElt();
+ miscElt.id = 0x27; // reserved for future use; ignored on decode
+ miscElt.data = new byte[]{0x12, 0x34};
+ smsHeader.miscEltList.add(miscElt);
+ } else {
+ // Even length header normally generated for concatenated SMS.
+ SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+ concatRef.refNumber = 0xEE;
+ concatRef.msgCount = total;
+ concatRef.seqNumber = index;
+ concatRef.isEightBits = true;
+ smsHeader.concatRef = concatRef;
+ }
+ byte[] encodeHeader = SmsHeader.toByteArray(smsHeader);
+ if (oddLengthHeader) {
+ assertEquals(4, encodeHeader.length); // 5 bytes with UDH length
+ } else {
+ assertEquals(5, encodeHeader.length); // 6 bytes with UDH length
+ }
UserData userData = new UserData();
- userData.payloadStr = "01234567";
+ userData.payloadStr = payload;
userData.userDataHeader = smsHeader;
bearerData.userData = userData;
byte[] encodedSms = BearerData.encode(bearerData);
BearerData revBearerData = BearerData.decode(encodedSms);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ assertTrue(revBearerData.hasUserDataHeader);
+ byte[] header = SmsHeader.toByteArray(revBearerData.userData.userDataHeader);
+ if (oddLengthHeader) {
+ assertEquals(4, header.length); // 5 bytes with UDH length
+ } else {
+ assertEquals(5, header.length); // 6 bytes with UDH length
+ }
+ assertTrue(Arrays.equals(encodeHeader, header));
}
@SmallTest
@@ -881,7 +910,27 @@ public class CdmaSmsTest extends AndroidTestCase {
if (isCdmaPhone) {
ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text2);
assertEquals(3, fragments.size());
+
+ for (int i = 0; i < 3; i++) {
+ encodeDecodeAssertEquals(fragments.get(i), i + 1, 3, false);
+ encodeDecodeAssertEquals(fragments.get(i), i + 1, 3, true);
+ }
}
+ // Test case for multi-part UTF-16 message.
+ String text3 = sUnicodeChars + sUnicodeChars + sUnicodeChars;
+ ted = SmsMessage.calculateLength(text3, false);
+ assertEquals(3, ted.msgCount);
+ assertEquals(189, ted.codeUnitCount);
+ assertEquals(3, ted.codeUnitSize);
+ if (isCdmaPhone) {
+ ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text3);
+ assertEquals(3, fragments.size());
+
+ for (int i = 0; i < 3; i++) {
+ encodeDecodeAssertEquals(fragments.get(i), i + 1, 3, false);
+ encodeDecodeAssertEquals(fragments.get(i), i + 1, 3, true);
+ }
+ }
}
}