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

Commit fc78f358 authored by Tammo Spalink's avatar Tammo Spalink
Browse files

for cdma concatenated (long) messages, replace ascii7bit with gsm7bit encoding

parent 83248c43
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