diff options
Diffstat (limited to 'telephony/java/android')
-rw-r--r-- | telephony/java/android/telephony/SmsManager.java | 52 | ||||
-rw-r--r-- | telephony/java/android/telephony/SmsMessage.java | 138 |
2 files changed, 110 insertions, 80 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; } /** |