split long messages with 4-byte unicode characters correctly also fix SmsMessage.calculateLength() for the same case refactor to remove some duplicated code BUG: 19535708 Change-Id: Ie2b46d54fdf09b5979e34d6aa1f7e1cb6dff56f8
diff --git a/src/java/android/telephony/SmsMessage.java b/src/java/android/telephony/SmsMessage.java index 9749618..3323078 100644 --- a/src/java/android/telephony/SmsMessage.java +++ b/src/java/android/telephony/SmsMessage.java
@@ -391,7 +391,7 @@ ted.languageTable, ted.languageShiftTable); } } else { // Assume unicode. - nextPos = pos + Math.min(limit / 2, textLen - pos); + nextPos = SmsMessageBase.findNextUnicodePosition(pos, limit, newMsgBody); } if ((nextPos <= pos) || (nextPos > textLen)) { Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
diff --git a/src/java/com/android/internal/telephony/SmsMessageBase.java b/src/java/com/android/internal/telephony/SmsMessageBase.java index b027b1e..1d50834 100644 --- a/src/java/com/android/internal/telephony/SmsMessageBase.java +++ b/src/java/com/android/internal/telephony/SmsMessageBase.java
@@ -16,11 +16,14 @@ package com.android.internal.telephony; +import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.SmsConstants; import com.android.internal.telephony.SmsHeader; +import java.text.BreakIterator; import java.util.Arrays; import android.provider.Telephony; +import android.telephony.SmsMessage; /** * Base class declaring the specific methods and members for SmsMessage. @@ -346,4 +349,70 @@ mIsEmail = Telephony.Mms.isEmailAddress(mEmailFrom); } + /** + * Find the next position to start a new fragment of a multipart SMS. + * + * @param currentPosition current start position of the fragment + * @param byteLimit maximum number of bytes in the fragment + * @param msgBody text of the SMS in UTF-16 encoding + * @return the position to start the next fragment + */ + public static int findNextUnicodePosition( + int currentPosition, int byteLimit, CharSequence msgBody) { + int nextPos = Math.min(currentPosition + byteLimit / 2, msgBody.length()); + // Check whether the fragment ends in a character boundary. Some characters take 4-bytes + // in UTF-16 encoding. Many carriers cannot handle + // a fragment correctly if it does not end at a character boundary. + if (nextPos < msgBody.length()) { + BreakIterator breakIterator = BreakIterator.getCharacterInstance(); + breakIterator.setText(msgBody.toString()); + if (!breakIterator.isBoundary(nextPos)) { + nextPos = breakIterator.preceding(nextPos); + } + } + return nextPos; + } + + /** + * Calculate the TextEncodingDetails of a message encoded in Unicode. + */ + public static TextEncodingDetails calcUnicodeEncodingDetails(CharSequence msgBody) { + TextEncodingDetails ted = new TextEncodingDetails(); + int octets = msgBody.length() * 2; + ted.codeUnitSize = SmsConstants.ENCODING_16BIT; + ted.codeUnitCount = msgBody.length(); + if (octets > SmsConstants.MAX_USER_DATA_BYTES) { + // If EMS is not supported, break down EMS into single segment SMS + // and add page info " x/y". + // In the case of UCS2 encoding type, we need 8 bytes for this + // but we only have 6 bytes from UDH, so truncate the limit for + // each segment by 2 bytes (1 char). + int maxUserDataBytesWithHeader = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER; + if (!SmsMessage.hasEmsSupport()) { + // make sure total number of segments is less than 10 + if (octets <= 9 * (maxUserDataBytesWithHeader - 2)) { + maxUserDataBytesWithHeader -= 2; + } + } + + int pos = 0; // Index in code units. + int msgCount = 0; + while (pos < msgBody.length()) { + int nextPos = findNextUnicodePosition(pos, maxUserDataBytesWithHeader, + msgBody); + if (nextPos == msgBody.length()) { + ted.codeUnitsRemaining = pos + maxUserDataBytesWithHeader / 2 - + msgBody.length(); + } + pos = nextPos; + msgCount++; + } + ted.msgCount = msgCount; + } else { + ted.msgCount = 1; + ted.codeUnitsRemaining = (SmsConstants.MAX_USER_DATA_BYTES - octets) / 2; + } + + return ted; + } }
diff --git a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java b/src/java/com/android/internal/telephony/cdma/sms/BearerData.java index 05800b5..58c6e55 100644 --- a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -24,9 +24,10 @@ import android.telephony.Rlog; import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.SmsConstants; import com.android.internal.telephony.SmsHeader; -import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; +import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.util.BitwiseInputStream; import com.android.internal.util.BitwiseOutputStream; @@ -489,31 +490,7 @@ isEntireMsg) { // We don't support single-segment EMS, so calculate for 16-bit // TODO: Consider supporting single-segment EMS - ted.codeUnitCount = msg.length(); - int octets = ted.codeUnitCount * 2; - if (octets > SmsConstants.MAX_USER_DATA_BYTES) { - // If EMS is not supported, break down EMS into single segment SMS - // and add page info " x/y". - // In the case of UCS2 encoding type, we need 8 bytes for this - // but we only have 6 bytes from UDH, so truncate the limit for - // each segment by 2 bytes (1 char). - int max_user_data_bytes_with_header = - SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER; - if (!android.telephony.SmsMessage.hasEmsSupport()) { - // make sure total number of segments is less than 10 - if (octets <= 9 * (max_user_data_bytes_with_header - 2)) - max_user_data_bytes_with_header -= 2; - } - - ted.msgCount = (octets + (max_user_data_bytes_with_header - 1)) / - max_user_data_bytes_with_header; - ted.codeUnitsRemaining = ((ted.msgCount * - max_user_data_bytes_with_header) - octets) / 2; - } else { - ted.msgCount = 1; - ted.codeUnitsRemaining = (SmsConstants.MAX_USER_DATA_BYTES - octets)/2; - } - ted.codeUnitSize = SmsConstants.ENCODING_16BIT; + return SmsMessageBase.calcUnicodeEncodingDetails(msg); } } return ted;
diff --git a/src/java/com/android/internal/telephony/gsm/SmsMessage.java b/src/java/com/android/internal/telephony/gsm/SmsMessage.java index a1f029f..0d9bed4 100644 --- a/src/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/src/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -777,7 +777,8 @@ } /** - * Calculate the number of septets needed to encode the message. + * Calculates the number of SMS's required to encode the message body and + * the number of characters remaining until the next message. * * @param msgBody the message to encode * @param use7bitOnly ignore (but still count) illegal characters if true @@ -795,31 +796,7 @@ } TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(newMsgBody, use7bitOnly); if (ted == null) { - ted = new TextEncodingDetails(); - int octets = newMsgBody.length() * 2; - ted.codeUnitCount = newMsgBody.length(); - if (octets > MAX_USER_DATA_BYTES) { - // If EMS is not supported, break down EMS into single segment SMS - // and add page info " x/y". - // In the case of UCS2 encoding type, we need 8 bytes for this - // but we only have 6 bytes from UDH, so truncate the limit for - // each segment by 2 bytes (1 char). - int max_user_data_bytes_with_header = MAX_USER_DATA_BYTES_WITH_HEADER; - if (!android.telephony.SmsMessage.hasEmsSupport()) { - // make sure total number of segments is less than 10 - if (octets <= 9 * (max_user_data_bytes_with_header - 2)) - max_user_data_bytes_with_header -= 2; - } - - ted.msgCount = (octets + (max_user_data_bytes_with_header - 1)) / - max_user_data_bytes_with_header; - ted.codeUnitsRemaining = ((ted.msgCount * - max_user_data_bytes_with_header) - octets) / 2; - } else { - ted.msgCount = 1; - ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2; - } - ted.codeUnitSize = ENCODING_16BIT; + return SmsMessageBase.calcUnicodeEncodingDetails(newMsgBody); } return ted; }