Merge change 133 into donut

* changes:
  Initial code for cdma sms encode and decode, in java, with simple tests.
This commit is contained in:
Android (Google) Code Review
2009-04-14 13:20:43 -07:00
13 changed files with 1156 additions and 1929 deletions

View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2008 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.internal.util;
/**
* An object that provides bitwise incremental read access to a byte array.
*
* This is useful, for example, when accessing a series of fields that
* may not be aligned on byte boundaries.
*
* NOTE -- This class is not threadsafe.
*/
public class BitwiseInputStream {
// The byte array being read from.
private byte[] mBuf;
// The current position offset, in bits, from the msb in byte 0.
private int mPos;
// The last valid bit offset.
private int mEnd;
/**
* An exception to report access problems.
*/
public static class AccessException extends Exception {
public AccessException(String s) {
super("BitwiseInputStream access failed: " + s);
}
}
/**
* Create object from byte array.
*
* @param buf a byte array containing data
*/
public BitwiseInputStream(byte buf[]) {
mBuf = buf;
mEnd = buf.length * 8;
mPos = 0;
}
/**
* Return the number of bit still available for reading.
*/
public int available() {
return mEnd - mPos;
}
/**
* Read some data and increment the current position.
*
* @param bits the amount of data to read (gte 0, lte 8)
*
* @return byte of read data (possibly partially filled, from lsb)
*/
public byte read(int bits) throws AccessException {
int index = mPos / 8;
int offset = 16 - (mPos % 8) - bits;
if ((bits < 0) || (bits > 8) || ((mPos + bits) > mEnd)) {
throw new AccessException("illegal read " +
"(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")");
}
int data = (mBuf[index] & 0xFF) << 8;
if (offset < 8) data |= (mBuf[index + 1] & 0xFF);
data >>>= offset;
data &= (-1 >>> (32 - bits));
mPos += bits;
return (byte)data;
}
/**
* Read data in bulk into a byte array and increment the current position.
*
* @param bits the amount of data to read
*
* @return newly allocated byte array of read data
*/
public byte[] readByteArray(int bits) throws AccessException {
int bytes = (bits / 8) + ((bits % 8) > 0 ? 1 : 0);
byte[] arr = new byte[bytes];
for (int i = 0; i < bytes; i++) {
int increment = Math.min(8, bits - (i * 8));
arr[i] = (byte)(read(increment) << (8 - increment));
}
return arr;
}
/**
* Increment the current position and ignore contained data.
*
* @param bits the amount by which to increment the position
*/
public void skip(int bits) throws AccessException {
if ((mPos + bits) > mEnd) {
throw new AccessException("illegal skip " +
"(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")");
}
mPos += bits;
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2008 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.internal.util;
/**
* An object that rovides bitwise incremental write access to a byte array.
*
* This is useful, for example, when writing a series of fields that
* may not be aligned on byte boundaries.
*
* NOTE -- This class is not threadsafe.
*/
public class BitwiseOutputStream {
// The byte array being written to, which will be grown as needed.
private byte[] mBuf;
// The current position offset, in bits, from the msb in byte 0.
private int mPos;
// The last bit offset, given the current buf length.
private int mEnd;
/**
* An exception to report access problems.
*/
public static class AccessException extends Exception {
public AccessException(String s) {
super("BitwiseOutputStream access failed: " + s);
}
}
/**
* Create object from hint at desired size.
*
* @param startingLength initial internal byte array length in bytes
*/
public BitwiseOutputStream(int startingLength) {
mBuf = new byte[startingLength];
mEnd = startingLength * 8;
mPos = 0;
}
/**
* Return byte array containing accumulated data, sized to just fit.
*
* @return newly allocated byte array
*/
public byte[] toByteArray() {
int len = (mPos / 8) + ((mPos % 8) > 0 ? 1 : 0);
byte[] newBuf = new byte[len];
System.arraycopy(mBuf, 0, newBuf, 0, len);
return newBuf;
}
/**
* Allocate a new internal buffer, if needed.
*
* @param bits additional bits to be accommodated
*/
private void possExpand(int bits) {
if ((mPos + bits) < mEnd) return;
byte[] newBuf = new byte[((mPos + bits) * 2) / 8];
System.arraycopy(mBuf, 0, newBuf, 0, mEnd / 8);
mBuf = newBuf;
}
/**
* Write some data and increment the current position.
*
* @param bits the amount of data to write (gte 0, lte 8)
* @param data to write, will be masked to expose only bits param from lsb
*/
public void write(int bits, int data) throws AccessException {
if ((bits < 0) || (bits > 8)) {
throw new AccessException("illegal write (" + bits + " bits)");
}
possExpand(bits);
data &= (-1 >>> (32 - bits));
int index = mPos / 8;
int offset = 16 - (mPos % 8) - bits;
data <<= offset;
mPos += bits;
mBuf[index] |= (data >>> 8);
if (offset < 8) mBuf[index + 1] |= (data & 0xFF);
}
/**
* Write data in bulk from a byte array and increment the current position.
*
* @param bits the amount of data to write
* @param arr the byte array containing data to be written
*/
public void writeByteArray(int bits, byte[] arr) throws AccessException {
for (int i = 0; i < arr.length; i++) {
int increment = Math.min(8, bits - (i * 8));
if (increment > 0) {
write(increment, (byte)(arr[i] >>> (8 - increment)));
}
}
}
/**
* Increment the current position, implicitly writing zeros.
*
* @param bits the amount by which to increment the position
*/
public void skip(int bits) {
possExpand(bits);
mPos += bits;
}
}

View File

@@ -20,20 +20,7 @@ import android.util.Log;
import com.android.internal.telephony.SmsHeader;
import java.util.Arrays;
import static android.telephony.SmsMessage.ENCODING_7BIT;
import static android.telephony.SmsMessage.ENCODING_16BIT;
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
import static android.telephony.SmsMessage.MessageClass;
import static com.android.internal.telephony.SmsAddress.TON_ABBREVIATED;
import static com.android.internal.telephony.SmsAddress.TON_ALPHANUMERIC;
import static com.android.internal.telephony.SmsAddress.TON_INTERNATIONAL;
import static com.android.internal.telephony.SmsAddress.TON_NATIONAL;
import static com.android.internal.telephony.SmsAddress.TON_NETWORK;
import static com.android.internal.telephony.SmsAddress.TON_SUBSCRIBER;
import static com.android.internal.telephony.SmsAddress.TON_UNKNOWN;
/**
* Base class declaring the specific methods and members for SmsMessage.
@@ -385,4 +372,3 @@ public abstract class SmsMessageBase {
}
}

View File

@@ -27,7 +27,6 @@ import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
import com.android.internal.telephony.cdma.sms.BearerData;
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
import com.android.internal.telephony.cdma.sms.SmsDataCoding;
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
import com.android.internal.telephony.cdma.sms.UserData;
@@ -50,23 +49,6 @@ import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
import static android.telephony.SmsMessage.MessageClass;
import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE;
import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY;
import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_PERMANENT;
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_DELIVER;
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_SUBMIT;
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_CANCELLATION;
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_DELIVERY_ACK;
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_USER_ACK;
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_READ_ACK;
import static com.android.internal.telephony.cdma.sms.CdmaSmsAddress.SMS_ADDRESS_MAX;
import static com.android.internal.telephony.cdma.sms.CdmaSmsAddress.SMS_SUBADDRESS_MAX;
import static com.android.internal.telephony.cdma.sms.SmsEnvelope.SMS_BEARER_DATA_MAX;
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_7BIT_ASCII;
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_GSM_7BIT_ALPHABET;
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_IA5;
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_OCTET;
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_UNICODE_16;
/**
* A Short Message Service message.
@@ -186,7 +168,7 @@ public class SmsMessage extends SmsMessageBase {
// ignore subaddress
p.readInt(); //p_cur->sSubAddress.subaddressType
p.readByte(); //p_cur->sSubAddress.odd
p.readInt(); //p_cur->sSubAddress.odd
count = p.readByte(); //p_cur->sSubAddress.number_of_digits
//p_cur->sSubAddress.digits[digitCount] :
for (int index=0; index < count; index++) {
@@ -309,15 +291,15 @@ public class SmsMessage extends SmsMessageBase {
int septetCount = GsmAlphabet.countGsmSeptets(message, true);
// User Data (and length)
uData.userData = message.getBytes();
uData.payload = message.getBytes();
if (uData.userData.length > MAX_USER_DATA_SEPTETS) {
if (uData.payload.length > MAX_USER_DATA_SEPTETS) {
// Message too long
return null;
}
// desired TP-Data-Coding-Scheme
uData.userDataEncoding = UserData.UD_ENCODING_GSM_7BIT_ALPHABET;
uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
// paddingBits not needed for UD_ENCODING_GSM_7BIT_ALPHABET
@@ -341,15 +323,15 @@ public class SmsMessage extends SmsMessageBase {
return null;
}
uData.userData = textPart;
uData.payload = textPart;
if (uData.userData.length > MAX_USER_DATA_BYTES) {
if (uData.payload.length > MAX_USER_DATA_BYTES) {
// Message too long
return null;
}
// TP-Data-Coding-Scheme
uData.userDataEncoding = UserData.UD_ENCODING_UNICODE_16;
uData.msgEncoding = UserData.ENCODING_UNICODE_16;
// sms header
if(headerData != null) {
@@ -425,8 +407,8 @@ public class SmsMessage extends SmsMessageBase {
// TP-Data-Coding-Scheme
// No class, 8 bit data
uData.userDataEncoding = UserData.UD_ENCODING_OCTET;
uData.userData = data;
uData.msgEncoding = UserData.ENCODING_OCTET;
uData.payload = data;
byte[] msgData = sms.getEnvelope(destinationAddress, statusReportRequested, uData,
true, true);
@@ -619,21 +601,21 @@ public class SmsMessage extends SmsMessageBase {
* Parses a SMS message from its BearerData stream. (mobile-terminated only)
*/
protected void parseSms() {
mBearerData = SmsDataCoding.decodeCdmaSms(mEnvelope.bearerData);
messageRef = mBearerData.messageID;
mBearerData = BearerData.decode(mEnvelope.bearerData);
messageRef = mBearerData.messageId;
// TP-Message-Type-Indicator
// (See 3GPP2 C.S0015-B, v2, 4.5.1)
int messageType = mBearerData.messageType;
switch (messageType) {
case MESSAGE_TYPE_USER_ACK:
case MESSAGE_TYPE_READ_ACK:
case MESSAGE_TYPE_DELIVER:
case BearerData.MESSAGE_TYPE_USER_ACK:
case BearerData.MESSAGE_TYPE_READ_ACK:
case BearerData.MESSAGE_TYPE_DELIVER:
// Deliver (mobile-terminated only)
parseSmsDeliver();
break;
case MESSAGE_TYPE_DELIVERY_ACK:
case BearerData.MESSAGE_TYPE_DELIVERY_ACK:
parseSmsDeliveryAck();
break;
@@ -699,22 +681,22 @@ public class SmsMessage extends SmsMessageBase {
return;
}
encodingType = uData.userDataEncoding;
encodingType = uData.msgEncoding;
// insert DCS-decoding here when type is supported by ril-library
userData = uData.userData;
userData = uData.payload;
userDataHeader = uData.userDataHeader;
switch (encodingType) {
case UD_ENCODING_GSM_7BIT_ALPHABET:
case UD_ENCODING_UNICODE_16:
case UserData.ENCODING_GSM_7BIT_ALPHABET:
case UserData.ENCODING_UNICODE_16:
// user data was already decoded by wmsts-library
messageBody = new String(userData);
break;
// data and unsupported encodings:
case UD_ENCODING_OCTET:
case UserData.ENCODING_OCTET:
default:
messageBody = null;
break;
@@ -771,7 +753,7 @@ public class SmsMessage extends SmsMessageBase {
if (useNewId) {
setNextMessageId();
}
mBearerData.messageID = nextMessageId;
mBearerData.messageId = nextMessageId;
// Set the reply options (See C.S0015-B, v2.0, 4.5.11)
if(statusReportRequested) {
@@ -795,7 +777,7 @@ public class SmsMessage extends SmsMessageBase {
// ** encode BearerData **
byte[] encodedBearerData = null;
try {
encodedBearerData = SmsDataCoding.encodeCdmaSms(mBearerData);
encodedBearerData = BearerData.encode(mBearerData);
} catch (Exception e) {
Log.e(LOG_TAG, "doGetSubmitPdu: EncodeCdmaSMS function in JNI interface failed: "
+ e.getMessage());

View File

@@ -16,7 +16,52 @@
package com.android.internal.telephony.cdma.sms;
import android.util.Log;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream;
/**
* XXX
*
*
*/
public final class BearerData{
private final static String LOG_TAG = "SMS";
/**
* Bearer Data Subparameter Indentifiers
* (See 3GPP2 C.S0015-B, v2.0, table 4.5-1)
*/
private final static byte SUBPARAM_MESSAGE_IDENTIFIER = 0x00;
private final static byte SUBPARAM_USER_DATA = 0x01;
private final static byte SUBPARAM_USER_REPONSE_CODE = 0x02;
private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP = 0x03;
//private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE = 0x04;
//private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE = 0x05;
//private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE = 0x06;
//private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE = 0x07;
//private final static byte SUBPARAM_PRIORITY_INDICATOR = 0x08;
//private final static byte SUBPARAM_PRIVACY_INDICATOR = 0x09;
private final static byte SUBPARAM_REPLY_OPTION = 0x0A;
private final static byte SUBPARAM_NUMBER_OF_MESSAGES = 0x0B;
//private final static byte SUBPARAM_ALERT_ON_MESSAGE_DELIVERY = 0x0C;
//private final static byte SUBPARAM_LANGUAGE_INDICATOR = 0x0D;
private final static byte SUBPARAM_CALLBACK_NUMBER = 0x0E;
//private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE = 0x0F;
//private final static byte SUBPARAM_MULTIPLE_ENCODING_USER_DATA = 0x10;
//private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX = 0x11;
//private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA = 0x12;
//private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS = 0x13;
private final static byte SUBPARAM_MESSAGE_STATUS = 0x14;
//private final static byte SUBPARAM_TP_FAILURE_CAUSE = 0x15;
//private final static byte SUBPARAM_ENHANCED_VMN = 0x16;
//private final static byte SUBPARAM_ENHANCED_VMN_ACK = 0x17;
// For completeness the following fields are listed, though not used yet.
/**
@@ -94,9 +139,6 @@ public final class BearerData{
public static final int ERROR_UNDEFINED = 0xFF;
public static final int STATUS_UNDEFINED = 0xFF;
/** Bit-mask indicating used fields for SmsDataCoding */
public int mask;
/**
* 4-bit value indicating the message type in accordance to
* table 4.5.1-1
@@ -109,7 +151,7 @@ public final class BearerData{
* (Special rules apply for WAP-messages.)
* (See 3GPP2 C.S0015-B, v2, 4.5.1)
*/
public int messageID;
public int messageId;
/**
* 1-bit value that indicates whether a User Data Header is present.
@@ -188,5 +230,440 @@ public final class BearerData{
*/
public int messageStatus = STATUS_UNDEFINED;
}
private static class CodingException extends Exception {
public CodingException(String s) {
super(s);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("BearerData:\n");
builder.append(" messageType: " + messageType + "\n");
builder.append(" messageId: " + (int)messageId + "\n");
builder.append(" hasUserDataHeader: " + hasUserDataHeader + "\n");
builder.append(" timeStamp: " + timeStamp + "\n");
builder.append(" userAckReq: " + userAckReq + "\n");
builder.append(" deliveryAckReq: " + deliveryAckReq + "\n");
builder.append(" readAckReq: " + readAckReq + "\n");
builder.append(" reportReq: " + reportReq + "\n");
builder.append(" numberOfMessages: " + numberOfMessages + "\n");
builder.append(" callbackNumber: " + callbackNumber + "\n");
builder.append(" displayMode: " + displayMode + "\n");
builder.append(" errorClass: " + errorClass + "\n");
builder.append(" messageStatus: " + messageStatus + "\n");
builder.append(" userData: " + userData + "\n");
return builder.toString();
}
private static void encodeMessageId(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException
{
outStream.write(8, 3);
outStream.write(4, bData.messageType);
outStream.write(8, bData.messageId >> 8);
outStream.write(8, bData.messageId);
outStream.write(1, bData.hasUserDataHeader ? 1 : 0);
outStream.skip(3);
}
private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException
{
int dataBits = (bData.userData.payload.length * 8) - bData.userData.paddingBits;
byte[] headerData = null;
if (bData.hasUserDataHeader) {
headerData = bData.userData.userDataHeader.toByteArray();
dataBits += headerData.length * 8;
}
int paramBits = dataBits + 13;
if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
(bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
paramBits += 8;
}
int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
int paddingBits = (paramBytes * 8) - paramBits;
outStream.write(8, paramBytes);
outStream.write(5, bData.userData.msgEncoding);
if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
(bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
outStream.write(8, bData.userData.msgType);
}
outStream.write(8, bData.userData.numFields);
if (headerData != null) outStream.writeByteArray(headerData.length * 8, headerData);
outStream.writeByteArray(dataBits, bData.userData.payload);
if (paddingBits > 0) outStream.write(paddingBits, 0);
}
private static void encodeReplyOption(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException
{
outStream.write(8, 1);
outStream.write(1, bData.userAckReq ? 1 : 0);
outStream.write(1, bData.deliveryAckReq ? 1 : 0);
outStream.write(1, bData.readAckReq ? 1 : 0);
outStream.write(1, bData.reportReq ? 1 : 0);
outStream.write(4, 0);
}
private static byte[] encodeDtmfSmsAddress(String address) {
int digits = address.length();
int dataBits = digits * 4;
int dataBytes = (dataBits / 8);
dataBytes += (dataBits % 8) > 0 ? 1 : 0;
byte[] rawData = new byte[dataBytes];
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;
rawData[i / 2] |= val << (4 - ((i % 2) * 4));
}
return rawData;
}
private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
try {
addr.origBytes = addr.address.getBytes("US-ASCII");
} catch (java.io.UnsupportedEncodingException ex) {
throw new CodingException("invalid SMS address, cannot convert to ASCII");
}
} else {
addr.origBytes = encodeDtmfSmsAddress(addr.address);
}
}
private static void encodeCallbackNumber(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException, CodingException
{
CdmaSmsAddress addr = bData.callbackNumber;
encodeCdmaSmsAddress(addr);
int paramBits = 9;
int dataBits = 0;
if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
paramBits += 7;
dataBits = addr.numberOfDigits * 8;
} else {
dataBits = addr.numberOfDigits * 4;
}
paramBits += dataBits;
int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
int paddingBits = (paramBytes * 8) - paramBits;
outStream.write(8, paramBytes);
outStream.write(1, addr.digitMode);
if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
outStream.write(3, addr.ton);
outStream.write(4, addr.numberPlan);
}
outStream.write(8, addr.numberOfDigits);
outStream.writeByteArray(dataBits, addr.origBytes);
if (paddingBits > 0) outStream.write(paddingBits, 0);
}
private static void encodeMsgStatus(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException
{
outStream.write(8, 1);
outStream.write(2, bData.errorClass);
outStream.write(6, bData.messageStatus);
}
private static void encodeMsgCount(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException
{
outStream.write(8, 1);
outStream.write(8, bData.numberOfMessages);
}
private static void encodeMsgCenterTimeStamp(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException
{
outStream.write(8, 6);
outStream.writeByteArray(6 * 8, bData.timeStamp);
}
/**
* Create serialized representation for BearerData object.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
*
* @param bearerData an instance of BearerData.
*
* @return data byta array of raw encoded SMS bearer data.
*/
public static byte[] encode(BearerData bData) {
try {
BitwiseOutputStream outStream = new BitwiseOutputStream(200);
outStream.write(8, SUBPARAM_MESSAGE_IDENTIFIER);
encodeMessageId(bData, outStream);
if (bData.userData != null) {
outStream.write(8, SUBPARAM_USER_DATA);
encodeUserData(bData, outStream);
}
if (bData.callbackNumber != null) {
outStream.write(8, SUBPARAM_CALLBACK_NUMBER);
encodeCallbackNumber(bData, outStream);
}
if (bData.userAckReq || bData.deliveryAckReq || bData.readAckReq || bData.reportReq) {
outStream.write(8, SUBPARAM_REPLY_OPTION);
encodeReplyOption(bData, outStream);
}
if (bData.numberOfMessages != 0) {
outStream.write(8, SUBPARAM_NUMBER_OF_MESSAGES);
encodeMsgCount(bData, outStream);
}
if (bData.timeStamp != null) {
outStream.write(8, SUBPARAM_MESSAGE_CENTER_TIME_STAMP);
encodeMsgCenterTimeStamp(bData, outStream);
}
return outStream.toByteArray();
} catch (BitwiseOutputStream.AccessException ex) {
Log.e(LOG_TAG, "BearerData encode failed: " + ex);
} catch (CodingException ex) {
Log.e(LOG_TAG, "BearerData encode failed: " + ex);
}
return null;
}
private static void decodeMessageId(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
if (inStream.read(8) != 3) {
throw new CodingException("MESSAGE_IDENTIFIER subparam size incorrect");
}
bData.messageType = inStream.read(4);
bData.messageId = inStream.read(8) << 8;
bData.messageId |= inStream.read(8);
bData.hasUserDataHeader = (inStream.read(1) == 1);
inStream.skip(3);
}
private static void decodeUserData(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException
{
byte paramBytes = inStream.read(8);
bData.userData = new UserData();
bData.userData.msgEncoding = inStream.read(5);
bData.userData.msgType = 0;
int consumedBits = 5;
if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
(bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
bData.userData.msgType = inStream.read(8);
consumedBits += 8;
}
bData.userData.numFields = inStream.read(8);
consumedBits += 8;
int dataBits = (paramBytes * 8) - consumedBits;
bData.userData.payload = inStream.readByteArray(dataBits);
}
private static String decodePayloadStr(byte[] data, int offset, int numFields, String format)
throws CodingException
{
try {
return new String(data, offset, numFields, format);
} catch (java.io.UnsupportedEncodingException ex) {
throw new CodingException("invalid ASCII user data code");
}
}
private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
throws CodingException
{
int offset = 0;
if (hasUserDataHeader) {
int UdhLen = userData.payload[0];
byte[] headerData = new byte[UdhLen];
System.arraycopy(userData.payload, 1, headerData, 0, UdhLen);
userData.userDataHeader = SmsHeader.parse(headerData);
}
switch (userData.msgEncoding) {
case UserData.ENCODING_GSM_7BIT_ALPHABET:
userData.payloadStr = GsmAlphabet.gsm7BitPackedToString(userData.payload,
offset, userData.numFields);
break;
case UserData.ENCODING_7BIT_ASCII:
userData.payloadStr = decodePayloadStr(userData.payload, offset,
userData.numFields, "US-ASCII");
break;
case UserData.ENCODING_UNICODE_16:
userData.payloadStr = decodePayloadStr(userData.payload, offset,
userData.numFields * 2, "UTF-16");
break;
default:
throw new CodingException("unsupported user data encoding ("
+ userData.msgEncoding + ")");
}
}
private static void decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
byte paramBytes = inStream.read(8);
if (paramBytes != 1) {
throw new CodingException("REPLY_OPTION subparam size incorrect");
}
bData.userAckReq = (inStream.read(1) == 1);
bData.deliveryAckReq = (inStream.read(1) == 1);
bData.readAckReq = (inStream.read(1) == 1);
bData.reportReq = (inStream.read(1) == 1);
inStream.skip(4);
}
private static void decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
if (inStream.read(8) != 1) {
throw new CodingException("NUMBER_OF_MESSAGES subparam size incorrect");
}
bData.numberOfMessages = inStream.read(8);
}
private static String decodeDtmfSmsAddress(byte[] rawData, int numFields)
throws CodingException
{
/* DTMF 4-bit digit encoding, defined in at
* 3GPP2 C.S005-D, v2.0, table 2.7.1.3.2.4-4 */
StringBuffer strBuf = new StringBuffer(numFields);
for (int i = 0; i < numFields; i++) {
int val = 0x0F & (rawData[i / 2] >>> (4 - ((i % 2) * 4)));
if ((val >= 1) && (val <= 9)) strBuf.append(Integer.toString(val, 10));
else if (val == 10) strBuf.append('0');
else if (val == 11) strBuf.append('*');
else if (val == 12) strBuf.append('#');
else throw new CodingException("invalid SMS address DTMF code (" + val + ")");
}
return strBuf.toString();
}
private static void decodeSmsAddress(CdmaSmsAddress addr) throws CodingException {
if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
try {
/* As specified in 3GPP2 C.S0015-B, v2, 4.5.15 -- actually
* just 7-bit ASCII encoding, with the MSB being zero. */
addr.address = new String(addr.origBytes, 0, addr.origBytes.length, "US-ASCII");
} catch (java.io.UnsupportedEncodingException ex) {
throw new CodingException("invalid SMS address ASCII code");
}
} else {
addr.address = decodeDtmfSmsAddress(addr.origBytes, addr.numberOfDigits);
}
}
private static void decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
byte paramBytes = inStream.read(8);
CdmaSmsAddress addr = new CdmaSmsAddress();
addr.digitMode = inStream.read(1);
byte fieldBits = 4;
byte consumedBits = 1;
if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
addr.ton = inStream.read(3);
addr.numberPlan = inStream.read(4);
fieldBits = 8;
consumedBits += 7;
}
addr.numberOfDigits = inStream.read(8);
consumedBits += 8;
int remainingBits = (paramBytes * 8) - consumedBits;
int dataBits = addr.numberOfDigits * fieldBits;
int paddingBits = remainingBits - dataBits;
if (remainingBits < dataBits) {
throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" +
"remainingBits " + remainingBits + ", dataBits " +
dataBits + ", paddingBits " + paddingBits + ")");
}
addr.origBytes = inStream.readByteArray(dataBits);
inStream.skip(paddingBits);
decodeSmsAddress(addr);
bData.callbackNumber = addr;
}
private static void decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
if (inStream.read(8) != 1) {
throw new CodingException("MESSAGE_STATUS subparam size incorrect");
}
bData.errorClass = inStream.read(2);
bData.messageStatus = inStream.read(6);
}
private static void decodeMsgCenterTimeStamp(BearerData bData,
BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
if (inStream.read(8) != 6) {
throw new CodingException("MESSAGE_CENTER_TIME_STAMP subparam size incorrect");
}
bData.timeStamp = inStream.readByteArray(6 * 8);
}
/**
* Create BearerData object from serialized representation.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
*
* @param smsData byte array of raw encoded SMS bearer data.
*
* @return an instance of BearerData.
*/
public static BearerData decode(byte[] smsData) {
try {
BitwiseInputStream inStream = new BitwiseInputStream(smsData);
BearerData bData = new BearerData();
int foundSubparamMask = 0;
while (inStream.available() > 0) {
int subparamId = inStream.read(8);
int subparamIdBit = 1 << subparamId;
if ((foundSubparamMask & subparamIdBit) != 0) {
throw new CodingException("illegal duplicate subparameter (" +
subparamId + ")");
}
foundSubparamMask |= subparamIdBit;
switch (subparamId) {
case SUBPARAM_MESSAGE_IDENTIFIER:
decodeMessageId(bData, inStream);
break;
case SUBPARAM_USER_DATA:
decodeUserData(bData, inStream);
break;
case SUBPARAM_REPLY_OPTION:
decodeReplyOption(bData, inStream);
break;
case SUBPARAM_NUMBER_OF_MESSAGES:
decodeMsgCount(bData, inStream);
break;
case SUBPARAM_CALLBACK_NUMBER:
decodeCallbackNumber(bData, inStream);
break;
case SUBPARAM_MESSAGE_STATUS:
decodeMsgStatus(bData, inStream);
break;
case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
decodeMsgCenterTimeStamp(bData, inStream);
break;
default:
throw new CodingException("unsupported bearer data subparameter ("
+ subparamId + ")");
}
}
if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
throw new CodingException("missing MESSAGE_IDENTIFIER subparam");
}
if (bData.userData != null) {
decodeUserDataPayload(bData.userData, bData.hasUserDataHeader);
}
return bData;
} catch (BitwiseInputStream.AccessException ex) {
Log.e(LOG_TAG, "BearerData decode failed: " + ex);
} catch (CodingException ex) {
Log.e(LOG_TAG, "BearerData decode failed: " + ex);
}
return null;
}
}

View File

@@ -17,6 +17,7 @@
package com.android.internal.telephony.cdma.sms;
import com.android.internal.telephony.SmsAddress;
import com.android.internal.util.HexDump;
public class CdmaSmsAddress extends SmsAddress {
/**
@@ -95,4 +96,18 @@ public class CdmaSmsAddress extends SmsAddress {
public CdmaSmsAddress(){
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("CdmaSmsAddress:\n");
builder.append(" digitMode: " + digitMode + "\n");
builder.append(" numberMode: " + numberMode + "\n");
builder.append(" numberPlan: " + numberPlan + "\n");
builder.append(" numberOfDigits: " + numberOfDigits + "\n");
builder.append(" ton: " + ton + "\n");
builder.append(" address: " + address + "\n");
builder.append(" origBytes: " + HexDump.toHexString(origBytes) + "\n");
return builder.toString();
}
}

View File

@@ -1,371 +0,0 @@
/*
* Copyright (C) 2007 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.internal.telephony.cdma.sms;
import com.android.internal.telephony.SmsHeader;
/*
* The SMSDataCoding class encodes and decodes CDMA SMS messages.
*/
public class SmsDataCoding {
private final static String TAG = "CDMA_SMS_JNI";
private final static int CDMA_SMS_WMS_MASK_BD_NULL = 0x00000000;
private final static int CDMA_SMS_WMS_MASK_BD_MSG_ID = 0x00000001;
private final static int CDMA_SMS_WMS_MASK_BD_USER_DATA = 0x00000002;
// private final static int CDMA_SMS_WMS_MASK_BD_USER_RESP = 0x00000004;
private final static int CDMA_SMS_WMS_MASK_BD_MC_TIME = 0x00000008;
// private final static int CDMA_SMS_WMS_MASK_BD_VALID_ABS = 0x00000010;
// private final static int CDMA_SMS_WMS_MASK_BD_VALID_REL = 0x00000020;
// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_ABS = 0x00000040;
// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_REL = 0x00000080;
// private final static int CDMA_SMS_WMS_MASK_BD_PRIORITY = 0x00000100;
// private final static int CDMA_SMS_WMS_MASK_BD_PRIVACY = 0x00000200;
// private final static int CDMA_SMS_WMS_MASK_BD_REPLY_OPTION = 0x00000400;
private final static int CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS = 0x00000800;
// private final static int CDMA_SMS_WMS_MASK_BD_ALERT = 0x00001000;
// private final static int CDMA_SMS_WMS_MASK_BD_LANGUAGE = 0x00002000;
private final static int CDMA_SMS_WMS_MASK_BD_CALLBACK = 0x00004000;
private final static int CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE = 0x00008000;
// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_DATA = 0x00010000;
// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_RESULT = 0x00020000;
// private final static int CDMA_SMS_WMS_MASK_BD_DEPOSIT_INDEX = 0x00040000;
// private final static int CDMA_SMS_WMS_MASK_BD_DELIVERY_STATUS = 0x00080000;
// private final static int CDMA_SMS_WMS_MASK_BD_IP_ADDRESS = 0x10000000;
// private final static int CDMA_SMS_WMS_MASK_BD_RSN_NO_NOTIFY = 0x20000000;
// private final static int CDMA_SMS_WMS_MASK_BD_OTHER = 0x40000000;
/**
* Successful operation.
*/
private static final int JNI_CDMA_SMS_SUCCESS = 0;
/**
* General failure.
*/
private static final int JNI_CDMA_SMS_FAILURE = 1;
/**
* Data length is out of length.
*/
private static final int JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE = 2;
/**
* Class name unknown.
*/
private static final int JNI_CDMA_SMS_CLASS_UNKNOWN = 3;
/**
* Field ID unknown.
*/
private static final int JNI_CDMA_SMS_FIELD_ID_UNKNOWN = 4;
/**
* Memory allocation failed.
*/
private static final int JNI_CDMA_SMS_OUT_OF_MEMORY = 5;
/**
* Encode SMS.
*
* @param bearerData an instance of BearerData.
*
* @return the encoded SMS as byte[].
*/
public static byte[] encodeCdmaSms(BearerData bearerData) {
byte[] encodedSms;
if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){
return null;
}
// check bearer data and generate bit mask
generateBearerDataBitMask(bearerData);
encodedSms = startEncoding(bearerData);
if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){
return null;
}
return encodedSms;
}
/**
* Decode SMS.
*
* @param SmsData the encoded SMS.
*
* @return an instance of BearerData.
*/
public static BearerData decodeCdmaSms(byte[] SmsData) {
BearerData bearerData;
if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){
return null;
}
bearerData = startDecoding(SmsData);
if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){
return null;
}
return bearerData;
}
private static void generateBearerDataBitMask(BearerData bearerData) {
// initial
bearerData.mask = CDMA_SMS_WMS_MASK_BD_NULL;
// check message type
if (bearerData.messageType != 0){
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MSG_ID;
}
// check mUserData
if (bearerData.userData != null){
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_USER_DATA;
}
// check mTimeStamp
if (bearerData.timeStamp != null){
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MC_TIME;
}
// check mNumberOfMessages
if (bearerData.numberOfMessages > 0){
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS;
}
// check mCallbackNumber
if(bearerData.callbackNumber != null){
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_CALLBACK;
}
// check DisplayMode
if(bearerData.displayMode == BearerData.DISPLAY_DEFAULT ||
bearerData.displayMode == BearerData.DISPLAY_IMMEDIATE ||
bearerData.displayMode == BearerData.DISPLAY_USER){
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE;
}
}
private static byte[] startEncoding(BearerData bearerData) {
int m_id;
byte[] m_data;
int dataLength;
byte[] encodedSms;
int nbrOfHeaders = 0;
if( nativeCdmaSmsSetBearerDataPrimitives(bearerData) == JNI_CDMA_SMS_FAILURE){
return null;
}
if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA){
if( nativeCdmaSmsSetUserData(bearerData.userData) == JNI_CDMA_SMS_FAILURE){
return null;
}
if (bearerData.userData.userDataHeader != null){
nbrOfHeaders = bearerData.userData.userDataHeader.nbrOfHeaders;
}
for (int i = 0; i < nbrOfHeaders; i++) {
m_id = bearerData.userData.userDataHeader.getElements().get(i).getID();
m_data = bearerData.userData.userDataHeader.getElements().get(i).getData();
dataLength = m_data.length;
if( nativeCdmaSmsSetUserDataHeader(m_id, m_data, dataLength, i)
== JNI_CDMA_SMS_FAILURE){
return null;
}
}
}
if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) {
if( nativeCdmaSmsSetSmsAddress(bearerData.callbackNumber) == JNI_CDMA_SMS_FAILURE){
return null;
}
}
/* call native method to encode SMS */
encodedSms = nativeCdmaSmsEncodeSms();
return encodedSms;
}
private static BearerData startDecoding(byte[] SmsData) {
BearerData bData = new BearerData();
byte[] udhData;
/* call native method to decode SMS */
if( nativeCdmaSmsDecodeSms(SmsData) == JNI_CDMA_SMS_FAILURE){
return null;
}
if( nativeCdmaSmsGetBearerDataPrimitives(bData) == JNI_CDMA_SMS_FAILURE){
return null;
}
if ((bData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA) {
bData.userData = new UserData();
if( nativeCdmaSmsGetUserData(bData.userData) == JNI_CDMA_SMS_FAILURE){
return null;
}
udhData = nativeCdmaSmsGetUserDataHeader();
if (udhData != null) {
bData.userData.userDataHeader = SmsHeader.parse(udhData);
}
}
if ((bData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) {
bData.callbackNumber = new CdmaSmsAddress();
if( nativeCdmaSmsGetSmsAddress(bData.callbackNumber) == JNI_CDMA_SMS_FAILURE){
return null;
}
}
return bData;
}
// native methods
/**
* native method: Allocate memory for clientBD structure
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsConstructClientBD();
/**
* native method: Free memory used for clientBD structure
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsDestructClientBD();
/**
* native method: fill clientBD structure with bearerData primitives
*
* @param bearerData an instance of BearerData.
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsSetBearerDataPrimitives(BearerData bearerData);
/**
* native method: fill bearerData primitives with clientBD variables
*
* @param bearerData an instance of BearerData.
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsGetBearerDataPrimitives(BearerData bearerData);
/**
* native method: fill clientBD.user_data with UserData primitives
*
* @param userData an instance of UserData.
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsSetUserData(UserData userData);
/**
* native method: fill UserData primitives with clientBD.user_data
*
* @param userData an instance of UserData.
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsGetUserData(UserData userData);
/**
* native method: fill clientBD.user_data.headers with UserDataHeader primitives
*
* @param ID ID of element.
* @param data element data.
* @param dataLength data length
* @param index index of element
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsSetUserDataHeader(
int ID, byte[] data, int dataLength, int index);
/**
* native method: fill UserDataHeader primitives with clientBD.user_data.headers
*
* @return user data headers
*/
private static native byte[] nativeCdmaSmsGetUserDataHeader();
/**
* native method: fill clientBD.callback with SmsAddress primitives
*
* @param smsAddr an instance of SmsAddress.
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsSetSmsAddress(CdmaSmsAddress smsAddr);
/**
* native method: fill SmsAddress primitives with clientBD.callback
*
* @param smsAddr an instance of SmsAddress.
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsGetSmsAddress(CdmaSmsAddress smsAddr);
/**
* native method: call encoding functions and get encoded SMS
*
* @return the encoded SMS
*/
private static native byte[] nativeCdmaSmsEncodeSms();
/**
* native method: call decode functions
*
* @param encodedSMS encoded SMS.
*
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
* #JNI_CDMA_SMS_FAILURE if fail.
*/
private static native int nativeCdmaSmsDecodeSms(byte[] encodedSMS);
/**
* Load the shared library to link the native methods.
*/
static {
try {
System.loadLibrary("cdma_sms_jni");
}
catch (UnsatisfiedLinkError ule) {
System.err.println("WARNING: Could not load cdma_sms_jni.so");
}
}
}

View File

@@ -17,24 +17,25 @@
package com.android.internal.telephony.cdma.sms;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.util.HexDump;
public class UserData{
/**
* Supported user data encoding types
* User data encoding types
* (See 3GPP2 C.R1001-F, v1.0, table 9.1-1)
*/
public static final int UD_ENCODING_OCTET = 0x00;
//public static final int UD_ENCODING_EXTENDED_PROTOCOL = 0x01;
public static final int UD_ENCODING_7BIT_ASCII = 0x02;
public static final int UD_ENCODING_IA5 = 0x03;
public static final int UD_ENCODING_UNICODE_16 = 0x04;
//public static final int UD_ENCODING_SHIFT_JIS = 0x05;
//public static final int UD_ENCODING_KOREAN = 0x06;
//public static final int UD_ENCODING_LATIN_HEBREW = 0x07;
//public static final int UD_ENCODING_LATIN = 0x08;
public static final int UD_ENCODING_GSM_7BIT_ALPHABET = 0x09;
//public static final int UD_ENCODING_GSM_DCS = 0x0A;
public static final int ENCODING_OCTET = 0x00;
public static final int ENCODING_IS91_EXTENDED_PROTOCOL = 0x01;
public static final int ENCODING_7BIT_ASCII = 0x02;
//public static final int ENCODING_IA5 = 0x03;
public static final int ENCODING_UNICODE_16 = 0x04;
//public static final int ENCODING_SHIFT_JIS = 0x05;
//public static final int ENCODING_KOREAN = 0x06;
//public static final int ENCODING_LATIN_HEBREW = 0x07;
//public static final int ENCODING_LATIN = 0x08;
public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09;
public static final int ENCODING_GSM_DCS = 0x0A;
/**
* Contains the data header of the user data
@@ -44,20 +45,37 @@ public class UserData{
/**
* Contains the data encoding type for the SMS message
*/
public int userDataEncoding;
public int msgEncoding;
// needed when encoding is IS91 or DCS (not supported yet):
//public int messageType;
// XXX needed when encoding is IS91 or DCS (not supported yet):
public int msgType;
/**
* Number of invalid bits in the last byte of data.
*/
public int paddingBits;
public int numFields;
/**
* Contains the user data of a SMS message
* (See 3GPP2 C.S0015-B, v2, 4.5.2)
*/
public byte[] userData;
public byte[] payload;
public String payloadStr;
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("UserData:\n");
builder.append(" msgEncoding: " + msgEncoding + "\n");
builder.append(" msgType: " + msgType + "\n");
builder.append(" paddingBits: " + paddingBits + "\n");
builder.append(" numFields: " + (int)numFields + "\n");
builder.append(" userDataHeader: " + userDataHeader + "\n");
builder.append(" payload: " + HexDump.toHexString(payload));
builder.append(" payloadStr: " + payloadStr);
return builder.toString();
}
}

View File

@@ -1,24 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
cdma_sms_jni.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libandroid_runtime \
libnativehelper
LOCAL_MODULE:= libcdma_sms_jni
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
hardware/ril/include/telephony
LOCAL_C_INCLUDES += hardware/ril/reference-cdma-sms
LOCAL_SHARED_LIBRARIES += libreference-cdma-sms
LOCAL_CFLAGS += -DREFERENCE_CDMA_SMS
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)

File diff suppressed because it is too large Load Diff

View File

@@ -1,159 +0,0 @@
/*
* Copyright (C) 2008 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.
*/
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_android_internal_telephony_cdma_sms_SmsDataCoding */
#ifndef _Included_com_android_internal_telephony_cdma_sms_SmsDataCoding
#define _Included_com_android_internal_telephony_cdma_sms_SmsDataCoding
#ifdef __cplusplus
extern "C" {
#endif
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_NULL
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_NULL 0L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_MSG_ID
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_MSG_ID 1L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_USER_DATA
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_USER_DATA 2L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_MC_TIME
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_MC_TIME 8L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS 2048L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_CALLBACK
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_CALLBACK 16384L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE 32768L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_SUCCESS
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_SUCCESS 0L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FAILURE
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FAILURE 1L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE 2L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_CLASS_UNKNOWN
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_CLASS_UNKNOWN 3L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FIELD_ID_UNKNOWN
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FIELD_ID_UNKNOWN 4L
#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_OUT_OF_MEMORY
#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_OUT_OF_MEMORY 5L
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsConstructClientBD
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsConstructClientBD
(JNIEnv *, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsDestructClientBD
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsDestructClientBD
(JNIEnv *, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsSetBearerDataPrimitives
* Signature: (Lcom/android/internal/telephony/cdma/sms/BearerData;)I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetBearerDataPrimitives
(JNIEnv *, jobject, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsGetBearerDataPrimitives
* Signature: (Lcom/android/internal/telephony/cdma/sms/BearerData;)I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetBearerDataPrimitives
(JNIEnv *, jobject, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsSetUserData
* Signature: (Lcom/android/internal/telephony/cdma/sms/UserData;)I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetUserData
(JNIEnv *, jobject, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsGetUserData
* Signature: (Lcom/android/internal/telephony/cdma/sms/UserData;)I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetUserData
(JNIEnv *, jobject, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsSetUserDataHeader
* Signature: (I[BII)I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetUserDataHeader
(JNIEnv *, jobject, jint, jbyteArray, jint, jint);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsGetUserDataHeader
* Signature: ()[B
*/
JNIEXPORT jbyteArray JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetUserDataHeader
(JNIEnv *, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsSetSmsAddress
* Signature: (Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;)I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetSmsAddress
(JNIEnv *, jobject, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsGetSmsAddress
* Signature: (Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;)I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetSmsAddress
(JNIEnv *, jobject, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsEncodeSms
* Signature: ()[B
*/
JNIEXPORT jbyteArray JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsEncodeSms
(JNIEnv *, jobject);
/*
* Class: com_android_internal_telephony_cdma_sms_SmsDataCoding
* Method: nativeCdmaSmsDecodeSms
* Signature: ([B)I
*/
JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsDecodeSms
(JNIEnv *, jobject, jbyteArray);
/**
* CDMA SMS return value defines
*/
#define JNI_SUCCESS \
com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_SUCCESS /**< Successful operation */
#define JNI_FAILURE \
com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FAILURE /**< General failure */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2006 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.unit_tests;
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;
public class BitwiseStreamsTest extends AndroidTestCase {
private final static String LOG_TAG = "BitwiseStreamsTest";
@SmallTest
public void testOne() throws Exception {
int offset = 3;
byte[] inBuf = HexDump.hexStringToByteArray("FFDD");
BitwiseOutputStream outStream = new BitwiseOutputStream(30);
outStream.skip(offset);
for (int i = 0; i < inBuf.length; i++) outStream.write(8, inBuf[i]);
byte[] outBuf = outStream.toByteArray();
BitwiseInputStream inStream = new BitwiseInputStream(outBuf);
byte[] inBufDup = new byte[inBuf.length];
inStream.skip(offset);
for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
}
@SmallTest
public void testTwo() throws Exception {
int offset = 3;
byte[] inBuf = HexDump.hexStringToByteArray("11d4f29c0e9ad3c36e72584e064d9b53");
BitwiseOutputStream outStream = new BitwiseOutputStream(30);
outStream.skip(offset);
for (int i = 0; i < inBuf.length; i++) outStream.write(8, inBuf[i]);
BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray());
inStream.skip(offset);
byte[] inBufDup = new byte[inBuf.length];
for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
}
@SmallTest
public void testThree() throws Exception {
int offset = 4;
byte[] inBuf = HexDump.hexStringToByteArray("00031040900112488ea794e0");
BitwiseOutputStream outStream = new BitwiseOutputStream(30);
outStream.skip(offset);
for (int i = 0; i < inBuf.length; i++) outStream.write(8, inBuf[i]);
BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray());
inStream.skip(offset);
byte[] inBufDup = new byte[inBuf.length];
for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
}
@SmallTest
public void testFour() throws Exception {
int offset = 7;
byte[] inBuf = HexDump.hexStringToByteArray("00031040900112488ea794e0");
BitwiseOutputStream outStream = new BitwiseOutputStream(30);
outStream.skip(offset);
for (int i = 0; i < inBuf.length; i++) {
outStream.write(5, inBuf[i] >>> 3);
outStream.write(3, inBuf[i] & 0x07);
}
BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray());
inStream.skip(offset);
byte[] inBufDup = new byte[inBuf.length];
for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8);
assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
}
}

View File

@@ -0,0 +1,273 @@
/*
* Copyright (C) 2006 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.unit_tests;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
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.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 java.util.Iterator;
import android.util.Log;
public class CdmaSmsTest extends AndroidTestCase {
private final static String LOG_TAG = "Cdma_Sms_Test";
private static UserData makeUserData(String msg) {
UserData userData = new UserData();
byte[] payload;
try {
payload = GsmAlphabet.stringToGsm7BitPacked(msg);
userData.payload = new byte[payload.length - 1];
for (int i = 0; i < userData.payload.length; i++) userData.payload[i] = payload[i + 1];
userData.numFields = payload[0];
userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7);
userData.paddingBits = 0; // XXX this is better, wtf?
userData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
} catch (com.android.internal.telephony.EncodeException ex) {
assertEquals(1, 0);
}
return userData;
}
@SmallTest
public void testStandardSms() throws Exception {
String pdu = "00031040900112488ea794e074d69e1b7392c270326cde9e98";
BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu));
assertEquals("Test standard SMS", bearerData.userData.payloadStr);
}
@SmallTest
public void testStandardSmsFeedback() throws Exception {
BearerData bearerData = new BearerData();
bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
bearerData.messageId = 0;
bearerData.hasUserDataHeader = false;
String payloadStr = "Test standard SMS";
bearerData.userData = makeUserData(payloadStr);
byte []encodedSms = BearerData.encode(bearerData);
BearerData revBearerData = BearerData.decode(encodedSms);
assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType);
assertEquals(0, revBearerData.messageId);
assertEquals(false, revBearerData.hasUserDataHeader);
assertEquals(UserData.ENCODING_GSM_7BIT_ALPHABET, revBearerData.userData.msgEncoding);
assertEquals(payloadStr.length(), revBearerData.userData.numFields);
assertEquals(payloadStr, revBearerData.userData.payloadStr);
}
@SmallTest
public void testAltUserDataFeedback() throws Exception {
try {
BearerData bearerData = new BearerData();
bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
bearerData.messageId = 0;
bearerData.hasUserDataHeader = false;
UserData userData = new UserData();
String str1 = "test ascii user data encoding";
userData.payload = str1.getBytes("US-ASCII");
userData.numFields = str1.length();
userData.paddingBits = 0;
userData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
bearerData.userData = userData;
byte []encodedSms = BearerData.encode(bearerData);
BearerData revBearerData = BearerData.decode(encodedSms);
assertEquals(str1, revBearerData.userData.payloadStr);
String str2 = "\u0160u\u1E5B\u0301r\u1ECFg\uD835\uDC1At\u00E9\u4E002\u3042";
userData.payload = str2.getBytes("UTF-16");
userData.numFields = str2.length() + 1;
userData.msgEncoding = UserData.ENCODING_UNICODE_16;
encodedSms = BearerData.encode(bearerData);
revBearerData = BearerData.decode(encodedSms);
assertEquals(str2, revBearerData.userData.payloadStr);
} catch (java.io.UnsupportedEncodingException ex) {
throw new RuntimeException("user data encoding error");
}
}
@SmallTest
public void testReplyOption() throws Exception {
String pdu1 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87450080a0180";
BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
assertEquals("Test Acknowledgement 1", bd1.userData.payloadStr);
assertEquals(true, bd1.userAckReq);
assertEquals(false, bd1.deliveryAckReq);
assertEquals(false, bd1.readAckReq);
assertEquals(false, bd1.reportReq);
String pdu2 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87490080a0140";
BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2));
assertEquals("Test Acknowledgement 2", bd2.userData.payloadStr);
assertEquals(false, bd2.userAckReq);
assertEquals(true, bd2.deliveryAckReq);
assertEquals(false, bd2.readAckReq);
assertEquals(false, bd2.reportReq);
String pdu3 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d874d0080a0120";
BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3));
assertEquals("Test Acknowledgement 3", bd3.userData.payloadStr);
assertEquals(false, bd3.userAckReq);
assertEquals(false, bd3.deliveryAckReq);
assertEquals(true, bd3.readAckReq);
assertEquals(false, bd3.reportReq);
String pdu4 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87510080a0110";
BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4));
assertEquals("Test Acknowledgement 4", bd4.userData.payloadStr);
assertEquals(false, bd4.userAckReq);
assertEquals(false, bd4.deliveryAckReq);
assertEquals(false, bd4.readAckReq);
assertEquals(true, bd4.reportReq);
}
@SmallTest
public void testReplyOptionFeedback() throws Exception {
BearerData bearerData = new BearerData();
bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
bearerData.messageId = 0;
bearerData.hasUserDataHeader = false;
bearerData.userData = makeUserData("test reply option");
bearerData.userAckReq = true;
byte []encodedSms = BearerData.encode(bearerData);
BearerData revBearerData = BearerData.decode(encodedSms);
assertEquals(true, revBearerData.userAckReq);
assertEquals(false, revBearerData.deliveryAckReq);
assertEquals(false, revBearerData.readAckReq);
assertEquals(false, revBearerData.reportReq);
bearerData.userAckReq = false;
bearerData.deliveryAckReq = true;
encodedSms = BearerData.encode(bearerData);
revBearerData = BearerData.decode(encodedSms);
assertEquals(false, revBearerData.userAckReq);
assertEquals(true, revBearerData.deliveryAckReq);
assertEquals(false, revBearerData.readAckReq);
assertEquals(false, revBearerData.reportReq);
bearerData.deliveryAckReq = false;
bearerData.readAckReq = true;
encodedSms = BearerData.encode(bearerData);
revBearerData = BearerData.decode(encodedSms);
assertEquals(false, revBearerData.userAckReq);
assertEquals(false, revBearerData.deliveryAckReq);
assertEquals(true, revBearerData.readAckReq);
assertEquals(false, revBearerData.reportReq);
bearerData.readAckReq = false;
bearerData.reportReq = true;
encodedSms = BearerData.encode(bearerData);
revBearerData = BearerData.decode(encodedSms);
assertEquals(false, revBearerData.userAckReq);
assertEquals(false, revBearerData.deliveryAckReq);
assertEquals(false, revBearerData.readAckReq);
assertEquals(true, revBearerData.reportReq);
}
@SmallTest
public void testNumberOfMessages() throws Exception {
String pdu1 = "000310409001124896a794e07595f69f199540ea759a0dc8e00b0163";
BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
assertEquals("Test Voice mail 99", bd1.userData.payloadStr);
assertEquals(99, bd1.numberOfMessages);
String pdu2 = "00031040900113489ea794e07595f69f199540ea759a0988c0600b0164";
BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2));
assertEquals("Test Voice mail 100", bd2.userData.payloadStr);
assertEquals(100, bd2.numberOfMessages);
}
@SmallTest
public void testNumberOfMessagesFeedback() throws Exception {
BearerData bearerData = new BearerData();
bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
bearerData.messageId = 0;
bearerData.hasUserDataHeader = false;
bearerData.userData = makeUserData("test message count");
bearerData.numberOfMessages = 27;
byte []encodedSms = BearerData.encode(bearerData);
BearerData revBearerData = BearerData.decode(encodedSms);
assertEquals(bearerData.numberOfMessages, revBearerData.numberOfMessages);
}
@SmallTest
public void testCallbackNum() throws Exception {
String pdu1 = "00031040900112488ea794e070d436cb638bc5e035ce2f97900e06910431323334";
BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
assertEquals("Test Callback nbr", bd1.userData.payloadStr);
assertEquals(CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR, bd1.callbackNumber.digitMode);
assertEquals(CdmaSmsAddress.TON_INTERNATIONAL_OR_IP, bd1.callbackNumber.ton);
assertEquals(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK, bd1.callbackNumber.numberMode);
assertEquals(CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY, bd1.callbackNumber.numberPlan);
assertEquals("1234", bd1.callbackNumber.address);
}
@SmallTest
public void testCallbackNumFeedback() throws Exception {
BearerData bearerData = new BearerData();
bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
bearerData.messageId = 0;
bearerData.hasUserDataHeader = false;
bearerData.userData = makeUserData("test callback number");
CdmaSmsAddress addr = new CdmaSmsAddress();
addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR;
addr.ton = CdmaSmsAddress.TON_NATIONAL_OR_EMAIL;
addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK;
addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN;
addr.address = "8005551212";
addr.numberOfDigits = (byte)addr.address.length();
bearerData.callbackNumber = addr;
byte []encodedSms = BearerData.encode(bearerData);
BearerData revBearerData = BearerData.decode(encodedSms);
CdmaSmsAddress revAddr = revBearerData.callbackNumber;
assertEquals(addr.digitMode, revAddr.digitMode);
assertEquals(addr.ton, revAddr.ton);
assertEquals(addr.numberMode, revAddr.numberMode);
assertEquals(addr.numberPlan, revAddr.numberPlan);
assertEquals(addr.numberOfDigits, revAddr.numberOfDigits);
assertEquals(addr.address, revAddr.address);
addr.address = "8*55#1012";
addr.numberOfDigits = (byte)addr.address.length();
addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF;
encodedSms = BearerData.encode(bearerData);
revBearerData = BearerData.decode(encodedSms);
revAddr = revBearerData.callbackNumber;
assertEquals(addr.digitMode, revAddr.digitMode);
assertEquals(addr.numberOfDigits, revAddr.numberOfDigits);
assertEquals(addr.address, revAddr.address);
}
@SmallTest
public void testMsgCenterTimeStampFeedback() throws Exception {
BearerData bearerData = new BearerData();
bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
bearerData.messageId = 0;
bearerData.hasUserDataHeader = false;
bearerData.userData = makeUserData("test message center timestamp");
bearerData.timeStamp = HexDump.hexStringToByteArray("112233445566");
byte []encodedSms = BearerData.encode(bearerData);
BearerData revBearerData = BearerData.decode(encodedSms);
assertEquals(HexDump.toHexString(bearerData.timeStamp),
HexDump.toHexString(revBearerData.timeStamp));
}
// XXX test messageId
// String pdu1 = "0003104090010d4866a794e07055965b91d040300c0100"; sid 12
// String pdu1 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0101"; sid 13
// Log.d(LOG_TAG, "revBearerData -- " + revBearerData);
}