for cdma concatenated (long) messages, replace ascii7bit with gsm7bit encoding
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 9395d66..890f930 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -22,7 +22,6 @@
import android.text.TextUtils;
import com.android.internal.telephony.EncodeException;
-import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.ISms;
import com.android.internal.telephony.IccConstants;
import com.android.internal.telephony.SmsRawData;
@@ -31,14 +30,12 @@
import java.util.Arrays;
import java.util.List;
-import static android.telephony.SmsMessage.ENCODING_7BIT;
-import static android.telephony.SmsMessage.ENCODING_8BIT;
-import static android.telephony.SmsMessage.ENCODING_16BIT;
-import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
-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;
+/*
+ * TODO(code review): Curious question... Why are a lot of these
+ * methods not declared as static, since they do not seem to require
+ * any local object state? Assumedly this cannot be changed without
+ * interfering with the API...
+ */
/**
* Manages SMS operations such as sending data, text, and pdu SMS messages.
@@ -88,7 +85,7 @@
}
/**
- * Divide a text message into several messages, none bigger than
+ * Divide a message text into several fragments, none bigger than
* the maximum SMS message size.
*
* @param text the original message. Must not be null.
@@ -96,40 +93,7 @@
* comprise the original message
*/
public ArrayList<String> divideMessage(String text) {
- int size = text.length();
- int[] params = SmsMessage.calculateLength(text, false);
- /* SmsMessage.calculateLength returns an int[4] with:
- * int[0] being the number of SMS's required,
- * int[1] the number of code units used,
- * int[2] is the number of code units remaining until the next message.
- * int[3] is the encoding type that should be used for the message.
- */
- int messageCount = params[0];
- int encodingType = params[3];
- ArrayList<String> result = new ArrayList<String>(messageCount);
-
- int start = 0;
- int limit;
-
- if (messageCount > 1) {
- limit = (encodingType == ENCODING_7BIT)?
- MAX_USER_DATA_SEPTETS_WITH_HEADER: MAX_USER_DATA_BYTES_WITH_HEADER;
- } else {
- limit = (encodingType == ENCODING_7BIT)?
- MAX_USER_DATA_SEPTETS: MAX_USER_DATA_BYTES;
- }
-
- try {
- while (start < size) {
- int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType);
- result.add(text.substring(start, end));
- start = end;
- }
- }
- catch (EncodeException e) {
- // ignore it.
- }
- return result;
+ return SmsMessage.fragmentText(text);
}
/**
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index b60da5a..775b0343 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -17,12 +17,17 @@
package android.telephony;
import android.os.Parcel;
+import android.util.Log;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.EncodeException;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
+
+import java.lang.Math;
+import java.util.ArrayList;
import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
@@ -44,19 +49,41 @@
UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
}
- /** Unknown encoding scheme (see TS 23.038) */
+ /**
+ * TODO(cleanup): given that we now have more than one possible
+ * 7bit encoding, this result starts to look rather vague and
+ * maybe confusing... If this is just an indication of code unit
+ * size, maybe that is no problem. Otherwise, should we try to
+ * create an aggregate collection of GSM and CDMA encodings? CDMA
+ * contains a superset of the encodings we use (it does not
+ * support 8-bit GSM, but we also do not use that encoding
+ * currently)... We could get rid of these and directly reference
+ * the CDMA encoding definitions...
+ */
+
+ /** User data text encoding code unit size */
public static final int ENCODING_UNKNOWN = 0;
- /** 7-bit encoding scheme (see TS 23.038) */
public static final int ENCODING_7BIT = 1;
- /** 8-bit encoding scheme (see TS 23.038) */
public static final int ENCODING_8BIT = 2;
- /** 16-bit encoding scheme (see TS 23.038) */
public static final int ENCODING_16BIT = 3;
/** The maximum number of payload bytes per message */
public static final int MAX_USER_DATA_BYTES = 140;
/**
+ * TODO(cleanup): It would be more flexible and less fragile to
+ * rewrite this (meaning get rid of the following constant) such
+ * that an actual UDH is taken into consideration (meaning its
+ * length is measured), allowing for messages that actually
+ * contain other UDH fields... Hence it is actually a shame to
+ * extend the API with this constant. If necessary, maybe define
+ * the size of such a header and let the math for calculating
+ * max_octets/septets be done elsewhere. And, while I am griping,
+ * if we use the word septet, we should use the word octet in
+ * corresponding places, not byte...
+ */
+
+ /**
* The maximum number of payload bytes per message if a user data header
* is present. This assumes the header only contains the
* CONCATENATED_8_BIT_REFERENCE element.
@@ -222,6 +249,15 @@
}
}
+ /*
+ * TODO(cleanup): It would make some sense if the result of
+ * preprocessing a message to determine the proper encoding (ie
+ * the resulting datastructure from calculateLength) could be
+ * passed as an argument to the actual final encoding function.
+ * This would better ensure that the logic behind size calculation
+ * actually matched the encoding.
+ */
+
/**
* Calculates the number of SMS's required to encode the message body and
* the number of characters remaining until the next message.
@@ -232,46 +268,76 @@
* space chars. If false, and if the messageBody contains
* non-7-bit encodable characters, length is calculated
* using a 16-bit encoding.
- * @return an int[4] with int[0] being the number of SMS's required, int[1]
- * the number of code units used, and int[2] is the number of code
- * units remaining until the next message. int[3] is the encoding
- * type that should be used for the message.
+ * @return an int[4] with int[0] being the number of SMS's
+ * required, int[1] the number of code units used, and
+ * int[2] is the number of code units remaining until the
+ * next message. int[3] is an indicator of the encoding
+ * code unit size (see the ENCODING_* definitions in this
+ * class).
*/
public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) {
int activePhone = TelephonyManager.getDefault().getPhoneType();
+ TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
+ com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly) :
+ com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly);
int ret[] = new int[4];
+ ret[0] = ted.msgCount;
+ ret[1] = ted.codeUnitCount;
+ ret[2] = ted.codeUnitsRemaining;
+ ret[3] = ted.codeUnitSize;
+ return ret;
+ }
- int septets = (PHONE_TYPE_CDMA == activePhone) ?
- com.android.internal.telephony.cdma.SmsMessage.calc7bitEncodedLength(msgBody,
- use7bitOnly) :
- com.android.internal.telephony.gsm.SmsMessage.calc7bitEncodedLength(msgBody,
- use7bitOnly);
- if (septets != -1) {
- ret[1] = septets;
- if (septets > MAX_USER_DATA_SEPTETS) {
- ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
- ret[2] = MAX_USER_DATA_SEPTETS_WITH_HEADER
- - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
- } else {
- ret[0] = 1;
- ret[2] = MAX_USER_DATA_SEPTETS - septets;
- }
- ret[3] = ENCODING_7BIT;
+ /**
+ * Divide a message text into several fragments, none bigger than
+ * the maximum SMS message text size.
+ *
+ * @param text text, must not be null.
+ * @return an <code>ArrayList</code> of strings that, in order,
+ * comprise the original msg text
+ */
+ public static ArrayList<String> fragmentText(String text) {
+ int activePhone = TelephonyManager.getDefault().getPhoneType();
+ TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
+ com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false) :
+ com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false);
+
+ // TODO(cleanup): The code here could be rolled into the logic
+ // below cleanly if these MAX_* constants were defined more
+ // flexibly...
+
+ int limit;
+ if (ted.msgCount > 1) {
+ limit = (ted.codeUnitSize == ENCODING_7BIT) ?
+ MAX_USER_DATA_SEPTETS_WITH_HEADER : MAX_USER_DATA_BYTES_WITH_HEADER;
} else {
- int octets = msgBody.length() * 2;
- ret[1] = msgBody.length();
- if (octets > MAX_USER_DATA_BYTES) {
- ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
- ret[2] = (MAX_USER_DATA_BYTES_WITH_HEADER
- - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
- } else {
- ret[0] = 1;
- ret[2] = (MAX_USER_DATA_BYTES - octets)/2;
- }
- ret[3] = ENCODING_16BIT;
+ limit = (ted.codeUnitSize == ENCODING_7BIT) ?
+ MAX_USER_DATA_SEPTETS : MAX_USER_DATA_BYTES;
}
- return ret;
+ int pos = 0; // Index in code units.
+ int textLen = text.length();
+ ArrayList<String> result = new ArrayList<String>(ted.msgCount);
+ while (pos < textLen) {
+ int nextPos = 0; // Counts code units.
+ if (ted.codeUnitSize == ENCODING_7BIT) {
+ if (PHONE_TYPE_CDMA == activePhone) {
+ nextPos = pos + Math.min(limit, textLen - pos);
+ } else {
+ nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit);
+ }
+ } else { // Assume unicode.
+ nextPos = pos + Math.min(limit / 2, textLen - pos);
+ }
+ if ((nextPos <= pos) || (nextPos > textLen)) {
+ Log.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
+ nextPos + " >= " + textLen + ")");
+ break;
+ }
+ result.add(text.substring(pos, nextPos));
+ pos = nextPos;
+ }
+ return result;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index 8e2941b..e8095e1 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -576,52 +576,6 @@
return size;
}
- /**
- * Returns the index into <code>s</code> of the first character
- * after <code>limit</code> octets have been reached, starting at
- * index <code>start</code>. This is used when dividing messages
- * in UCS2 encoding into units within the SMS message size limit.
- *
- * @param s source string
- * @param start index of where to start counting septets
- * @param limit maximum septets to include,
- * e.g. <code>MAX_USER_DATA_BYTES</code>
- * @return index of first character that won't fit, or the length
- * of the entire string if everything fits
- */
- public static int
- findUCS2LimitIndex(String s, int start, int limit) {
- int numCharToBeEncoded = s.length() - start;
- return ((numCharToBeEncoded*2 > limit)? limit/2: numCharToBeEncoded) + start;
- }
-
- /**
- * Returns the index into <code>s</code> of the first character
- * after <code>limit</code> septets/octets have been reached
- * according to the <code>encodingType</code>, starting at
- * index <code>start</code>. This is used when dividing messages
- * units within the SMS message size limit.
- *
- * @param s source string
- * @param start index of where to start counting septets
- * @param limit maximum septets to include,
- * e.g. <code>MAX_USER_DATA_BYTES</code>
- * @return index of first character that won't fit, or the length
- * of the entire string if everything fits
- */
- public static int
- findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException {
- if (encodingType == SmsMessage.ENCODING_7BIT) {
- return findGsmSeptetLimitIndex(s, start, limit);
- }
- else if (encodingType == SmsMessage.ENCODING_16BIT) {
- return findUCS2LimitIndex(s, start, limit);
- }
- else {
- throw new EncodeException("Unsupported encoding type: " + encodingType);
- }
- }
-
// Set in the static initializer
private static int sGsmSpaceChar;
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 4d32c35..3c7dd45 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -86,6 +86,38 @@
/** TP-Message-Reference - Message Reference of sent message. @hide */
public int messageRef;
+ /**
+ * For a specific text string, this object describes protocol
+ * properties of encoding it for transmission as message user
+ * data.
+ */
+ public static class TextEncodingDetails {
+ /**
+ *The number of SMS's required to encode the text.
+ */
+ public int msgCount;
+
+ /**
+ * The number of code units consumed so far, where code units
+ * are basically characters in the encoding -- for example,
+ * septets for the standard ASCII and GSM encodings, and 16
+ * bits for Unicode.
+ */
+ public int codeUnitCount;
+
+ /**
+ * How many code units are still available without spilling
+ * into an additional message.
+ */
+ public int codeUnitsRemaining;
+
+ /**
+ * The encoding code unit size (specified using
+ * android.telephony.SmsMessage ENCODING_*).
+ */
+ public int codeUnitSize;
+ }
+
public static abstract class SubmitPduBase {
public byte[] encodedScAddress; // Null if not applicable.
public byte[] encodedMessage;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 79e1cd6..2b4a700 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -34,6 +34,7 @@
import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.cdma.SmsMessage;
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
+import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
import java.io.ByteArrayOutputStream;
@@ -302,8 +303,12 @@
deliveryIntent = deliveryIntents.get(i);
}
- SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(scAddr, destAddr,
- parts.get(i), deliveryIntent != null, smsHeader);
+ UserData uData = new UserData();
+ uData.payloadStr = parts.get(i);
+ uData.userDataHeader = smsHeader;
+
+ SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destAddr,
+ uData, deliveryIntent != null);
sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index bbdd0dd..63d2c47 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -357,14 +357,18 @@
}
/**
- * Calculate the number of septets needed to encode the message.
+ * Get an SMS-SUBMIT PDU for a data message to a destination address & port
*
- * @param messageBody the message to encode
- * @param force ignore (but still count) illegal characters if true
- * @return septet count, or -1 on failure
+ * @param destAddr the address of the destination for the message
+ * @param userDara the data for the message
+ * @param statusReportRequested Indicates whether a report is requested for this message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
*/
- public static int calc7bitEncodedLength(CharSequence msgBody, boolean force) {
- return BearerData.calc7bitEncodedLength(msgBody.toString(), force);
+ public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
+ boolean statusReportRequested) {
+ return privateGetSubmitPdu(destAddr, statusReportRequested, userData);
}
/**
@@ -442,6 +446,18 @@
}
/**
+ * Calculate the number of septets needed to encode the message.
+ *
+ * @param messageBody the message to encode
+ * @param use7bitOnly ignore (but still count) illegal characters if true
+ * @return TextEncodingDetails
+ */
+ public static TextEncodingDetails calculateLength(CharSequence messageBody,
+ boolean use7bitOnly) {
+ return BearerData.calcTextEncodingDetails(messageBody.toString(), use7bitOnly);
+ }
+
+ /**
* Returns the teleservice type of the message.
* @return the teleservice:
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET},
@@ -627,12 +643,15 @@
bearerData.userData = userData;
bearerData.hasUserDataHeader = (userData.userDataHeader != null);
+ int teleservice = bearerData.hasUserDataHeader ?
+ SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
+
byte[] encodedBearerData = BearerData.encode(bearerData);
if (encodedBearerData == null) return null;
SmsEnvelope envelope = new SmsEnvelope();
envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
- envelope.teleService = SmsEnvelope.TELESERVICE_WMT;
+ envelope.teleService = teleservice;
envelope.destAddress = destAddr;
envelope.bearerReply = RETURN_ACK;
envelope.bearerData = encodedBearerData;
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 3c45aa4..a835dee 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.cdma.sms;
import android.util.Log;
+import android.util.SparseIntArray;
import android.telephony.SmsMessage;
@@ -26,6 +27,7 @@
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
import com.android.internal.util.HexDump;
import com.android.internal.util.BitwiseInputStream;
@@ -35,7 +37,7 @@
/**
* An object to encode and decode CDMA SMS bearer data.
*/
-public final class BearerData{
+public final class BearerData {
private final static String LOG_TAG = "SMS";
/**
@@ -385,56 +387,61 @@
outStream.skip(3);
}
- private static class SeptetData {
- byte data[];
- int septetCount;
-
- SeptetData(byte[] data, int septetCount) {
- this.data = data;
- this.septetCount = septetCount;
- }
- }
-
- private static SeptetData encode7bitAscii(String msg, boolean force)
- throws CodingException
- {
- try {
- BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length());
- byte[] expandedData = msg.getBytes("US-ASCII");
- for (int i = 0; i < expandedData.length; i++) {
- int charCode = expandedData[i];
- // Test ourselves for ASCII membership, since Java seems not to care.
- if ((charCode < UserData.PRINTABLE_ASCII_MIN_INDEX) ||
- (charCode > UserData.PRINTABLE_ASCII_MAX_INDEX)) {
- if (force) {
- outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
- } else {
- throw new CodingException("illegal ASCII code (" + charCode + ")");
- }
- } else {
- outStream.write(7, expandedData[i]);
- }
+ private static int countAsciiSeptets(CharSequence msg, boolean force) {
+ int msgLen = msg.length();
+ if (force) return msgLen;
+ for (int i = 0; i < msgLen; i++) {
+ if (UserData.charToAscii.get(msg.charAt(i), -1) == -1) {
+ return -1;
}
- return new SeptetData(outStream.toByteArray(), expandedData.length);
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("7bit ASCII encode failed: " + ex);
- } catch (BitwiseOutputStream.AccessException ex) {
- throw new CodingException("7bit ASCII encode failed: " + ex);
}
+ return msgLen;
}
/**
- * Calculate the number of septets needed to encode the message.
+ * Calculate the message text encoding length, fragmentation, and other details.
*
* @param force ignore (but still count) illegal characters if true
* @return septet count, or -1 on failure
*/
- public static int calc7bitEncodedLength(String msg, boolean force) {
+ public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg,
+ boolean force7BitEncoding) {
+ TextEncodingDetails ted;
+ int septets = countAsciiSeptets(msg, force7BitEncoding);
+ if (septets != -1 && septets <= SmsMessage.MAX_USER_DATA_SEPTETS) {
+ ted = new TextEncodingDetails();
+ ted.msgCount = 1;
+ ted.codeUnitCount = septets;
+ ted.codeUnitsRemaining = SmsMessage.MAX_USER_DATA_SEPTETS - septets;
+ ted.codeUnitSize = SmsMessage.ENCODING_7BIT;
+ } else {
+ ted = com.android.internal.telephony.gsm.SmsMessage.calculateLength(
+ msg, force7BitEncoding);
+ }
+ return ted;
+ }
+
+ private static byte[] encode7bitAscii(String msg, boolean force)
+ throws CodingException
+ {
try {
- SeptetData data = encode7bitAscii(msg, force);
- return data.septetCount;
- } catch (CodingException ex) {
- return -1;
+ BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length());
+ int msgLen = msg.length();
+ for (int i = 0; i < msgLen; i++) {
+ int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
+ if (charCode == -1) {
+ if (force) {
+ outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
+ } else {
+ throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
+ }
+ } else {
+ outStream.write(7, charCode);
+ }
+ }
+ return outStream.toByteArray();
+ } catch (BitwiseOutputStream.AccessException ex) {
+ throw new CodingException("7bit ASCII encode failed: " + ex);
}
}
@@ -452,8 +459,10 @@
throws CodingException
{
try {
- /**
- * TODO(cleanup): find some way to do this without the copy.
+ /*
+ * TODO(cleanup): It would be nice if GsmAlphabet provided
+ * an option to produce just the data without prepending
+ * the length.
*/
byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg);
byte []data = new byte[fullData.length - 1];
@@ -470,54 +479,65 @@
throws CodingException
{
byte[] headerData = null;
+ // TODO: if there is a header, meaning EMS mode, we probably
+ // also want the total UD length prior to the UDH length...
if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader);
int headerDataLen = (headerData == null) ? 0 : headerData.length + 1; // + length octet
byte[] payloadData;
+ int codeUnitCount;
if (uData.msgEncodingSet) {
if (uData.msgEncoding == UserData.ENCODING_OCTET) {
if (uData.payload == null) {
Log.e(LOG_TAG, "user data with octet encoding but null payload");
- // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
payloadData = new byte[0];
+ codeUnitCount = 0;
} else {
payloadData = uData.payload;
+ codeUnitCount = uData.payload.length;
}
} else {
if (uData.payloadStr == null) {
Log.e(LOG_TAG, "non-octet user data with null payloadStr");
- // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
uData.payloadStr = "";
}
if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
payloadData = encode7bitGsm(uData.payloadStr);
+ codeUnitCount = (payloadData.length * 8) / 7;
} else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
- SeptetData septetData = encode7bitAscii(uData.payloadStr, true);
- payloadData = septetData.data;
+ payloadData = encode7bitAscii(uData.payloadStr, true);
+ codeUnitCount = uData.payloadStr.length();
} else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
payloadData = encodeUtf16(uData.payloadStr);
+ codeUnitCount = uData.payloadStr.length();
} else {
throw new CodingException("unsupported user data encoding (" +
uData.msgEncoding + ")");
}
- uData.numFields = uData.payloadStr.length();
}
} else {
if (uData.payloadStr == null) {
Log.e(LOG_TAG, "user data with null payloadStr");
- // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
uData.payloadStr = "";
}
try {
- SeptetData septetData = encode7bitAscii(uData.payloadStr, false);
- payloadData = septetData.data;
- uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
+ if (headerData == null) {
+ payloadData = encode7bitAscii(uData.payloadStr, false);
+ codeUnitCount = uData.payloadStr.length();
+ uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
+ } else {
+ // If there is a header, we are in EMS mode, in
+ // which case we use GSM encodings.
+ payloadData = encode7bitGsm(uData.payloadStr);
+ codeUnitCount = (payloadData.length * 8) / 7;
+ uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+ }
} catch (CodingException ex) {
payloadData = encodeUtf16(uData.payloadStr);
+ codeUnitCount = uData.payloadStr.length();
uData.msgEncoding = UserData.ENCODING_UNICODE_16;
}
uData.msgEncodingSet = true;
- uData.numFields = uData.payloadStr.length();
}
int totalLength = payloadData.length + headerDataLen;
@@ -526,6 +546,7 @@
" > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
}
+ uData.numFields = codeUnitCount;
uData.payload = new byte[totalLength];
if (headerData != null) {
uData.payload[0] = (byte)headerData.length;
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
index 8d4e769..d8a48cc 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony.cdma.sms;
+import android.util.SparseIntArray;
+
import com.android.internal.telephony.SmsHeader;
import com.android.internal.util.HexDump;
@@ -40,6 +42,10 @@
/**
* IA5 data encoding character mappings.
* (See CCITT Rec. T.50 Tables 1 and 3)
+ *
+ * Note this mapping is the the same as for printable ASCII
+ * characters, with a 0x20 offset, meaning that the ASCII SPACE
+ * character occurs with code 0x20.
*/
public static final char[] IA5_MAP = {
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
@@ -61,7 +67,16 @@
* Only elements between these indices in the ASCII table are printable.
*/
public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20;
- public static final int PRINTABLE_ASCII_MAX_INDEX = 0x7F;
+ public static final int ASCII_LF_INDEX = 0x0A;
+ public static final int ASCII_CR_INDEX = 0x0D;
+ public static final SparseIntArray charToAscii = new SparseIntArray();
+ static {
+ for (int i = 0; i < IA5_MAP.length; i++) {
+ charToAscii.put(IA5_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i);
+ }
+ charToAscii.put('\r', ASCII_LF_INDEX);
+ charToAscii.put('\n', ASCII_CR_INDEX);
+ }
/**
* Mapping for IA5 values less than 32 are flow control signals
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index a15bbdf..f1207e4 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -26,6 +26,7 @@
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
@@ -742,17 +743,39 @@
/**
* Calculate the number of septets needed to encode the message.
*
- * @param messageBody the message to encode
- * @param force ignore (but still count) illegal characters if true
- * @return septet count, or -1 on failure
+ * @param msgBody the message to encode
+ * @param use7bitOnly ignore (but still count) illegal characters if true
+ * @return TextEncodingDetails
*/
- public static int calc7bitEncodedLength(CharSequence messageBody, boolean force) {
+ public static TextEncodingDetails calculateLength(CharSequence msgBody,
+ boolean use7bitOnly) {
+ TextEncodingDetails ted = new TextEncodingDetails();
try {
- return GsmAlphabet.countGsmSeptets(messageBody, !force);
+ int septets = GsmAlphabet.countGsmSeptets(msgBody, !use7bitOnly);
+ ted.codeUnitCount = septets;
+ if (septets > MAX_USER_DATA_SEPTETS) {
+ ted.msgCount = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
+ ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS_WITH_HEADER
+ - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
+ } else {
+ ted.msgCount = 1;
+ ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS - septets;
+ }
+ ted.codeUnitSize = ENCODING_7BIT;
} catch (EncodeException ex) {
- /* Just fall through to the -1 error result below. */
+ int octets = msgBody.length() * 2;
+ ted.codeUnitCount = msgBody.length();
+ if (octets > MAX_USER_DATA_BYTES) {
+ ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
+ ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
+ - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+ } else {
+ ted.msgCount = 1;
+ ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
+ }
+ ted.codeUnitSize = ENCODING_16BIT;
}
- return -1;
+ return ted;
}
/** {@inheritDoc} */