Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8696d703 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 3874 into donut

* changes:
  for cdma concatenated (long) messages, replace ascii7bit with gsm7bit encoding
parents 77dcf735 fc78f358
Loading
Loading
Loading
Loading
+8 −44
Original line number Diff line number Diff line
@@ -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);
    }

    /**
+102 −36
Original line number Diff line number Diff line
@@ -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,18 +49,40 @@ 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
@@ -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);
    /**
     * 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 {
                ret[0] = 1;
                ret[2] = MAX_USER_DATA_SEPTETS - septets;
            limit = (ted.codeUnitSize == ENCODING_7BIT) ?
                MAX_USER_DATA_SEPTETS : MAX_USER_DATA_BYTES;
        }
            ret[3] = ENCODING_7BIT;
        } 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;

        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 {
                ret[0] = 1;
                ret[2] = (MAX_USER_DATA_BYTES - octets)/2;
                    nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit);
                }
            ret[3] = ENCODING_16BIT;
            } else {  // Assume unicode.
                nextPos = pos + Math.min(limit / 2, textLen - pos);
            }

        return ret;
            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;
    }

    /**
+0 −46
Original line number Diff line number Diff line
@@ -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;

+32 −0
Original line number Diff line number Diff line
@@ -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;
+7 −2
Original line number Diff line number Diff line
@@ -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);
        }
Loading