diff options
| author | Tammo Spalink <tammo@google.com> | 2009-06-11 17:36:37 +0800 |
|---|---|---|
| committer | Tammo Spalink <tammo@google.com> | 2009-06-18 14:57:06 +0800 |
| commit | fc78f358cb1d1cee99758bcd6ef998a122ef27c9 (patch) | |
| tree | 241ad4b107330ac381dc82290b4dbcc97ea7c89b /telephony/java | |
| parent | 83248c432ffe2e2a17abbc8e4960c26574b46bca (diff) | |
| download | frameworks_base-fc78f358cb1d1cee99758bcd6ef998a122ef27c9.zip frameworks_base-fc78f358cb1d1cee99758bcd6ef998a122ef27c9.tar.gz frameworks_base-fc78f358cb1d1cee99758bcd6ef998a122ef27c9.tar.bz2 | |
for cdma concatenated (long) messages, replace ascii7bit with gsm7bit encoding
Diffstat (limited to 'telephony/java')
9 files changed, 288 insertions, 189 deletions
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.os.ServiceManager; 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.ArrayList; 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 @@ public final class SmsManager { } /** - * 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 @@ public final class SmsManager { * 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..775b034 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 @@ public class SmsMessage { 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 @@ public class SmsMessage { } } + /* + * 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 @@ public class SmsMessage { * 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 @@ public class GsmAlphabet { 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 @@ public abstract class SmsMessageBase { /** 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.SmsMessageBase; 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 @@ final class CdmaSMSDispatcher extends SMSDispatcher { 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 @@ public class SmsMessage extends SmsMessageBase { } /** - * 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 @@ public class SmsMessage extends SmsMessageBase { } /** + * 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 @@ public class SmsMessage extends SmsMessageBase { 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.IccUtils; 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 @@ import com.android.internal.util.BitwiseOutputStream; /** * 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,59 +387,64 @@ public final class BearerData{ outStream.skip(3); } - private static class SeptetData { - byte data[]; - int septetCount; + 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 msgLen; + } - SeptetData(byte[] data, int septetCount) { - this.data = data; - this.septetCount = septetCount; + /** + * 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 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 SeptetData encode7bitAscii(String msg, boolean force) + private static byte[] 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)) { + 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("illegal ASCII code (" + charCode + ")"); + throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")"); } } else { - outStream.write(7, expandedData[i]); + outStream.write(7, charCode); } } - return new SeptetData(outStream.toByteArray(), expandedData.length); - } catch (java.io.UnsupportedEncodingException ex) { - throw new CodingException("7bit ASCII encode failed: " + ex); + return outStream.toByteArray(); } catch (BitwiseOutputStream.AccessException ex) { throw new CodingException("7bit ASCII encode failed: " + ex); } } - /** - * Calculate the number of septets needed to encode the message. - * - * @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) { - try { - SeptetData data = encode7bitAscii(msg, force); - return data.septetCount; - } catch (CodingException ex) { - return -1; - } - } - private static byte[] encodeUtf16(String msg) throws CodingException { @@ -452,8 +459,10 @@ public final class BearerData{ 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 @@ public final class BearerData{ 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 @@ public final class BearerData{ " > " + 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 @@ public class UserData { /** * 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 @@ public class UserData { * 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.EncodeException; 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 @@ public class SmsMessage extends SmsMessageBase{ /** * 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} */ |
