FileDocCategorySizeDatePackage
SmsMessage.javaAPI DocAndroid 5.1 API42294Thu Mar 12 22:22:54 GMT 2015com.android.internal.telephony.cdma

SmsMessage

public class SmsMessage extends com.android.internal.telephony.SmsMessageBase
A Short Message Service message.

Fields Summary
static final String
LOG_TAG
private static final String
LOGGABLE_TAG
private static final boolean
VDBG
private static final byte
TELESERVICE_IDENTIFIER
private static final byte
SERVICE_CATEGORY
private static final byte
ORIGINATING_ADDRESS
private static final byte
ORIGINATING_SUB_ADDRESS
private static final byte
DESTINATION_ADDRESS
private static final byte
DESTINATION_SUB_ADDRESS
private static final byte
BEARER_REPLY_OPTION
private static final byte
CAUSE_CODES
private static final byte
BEARER_DATA
private int
status
Status of a previously submitted SMS. This field applies to SMS Delivery Acknowledge messages. 0 indicates success; Here, the error class is defined by the bits from 9-8, the status code by the bits from 7-0. See C.S0015-B, v2.0, 4.5.21 for a detailed description of possible values.
private static final int
RETURN_NO_ACK
Specifies if a return of an acknowledgment is requested for send SMS
private static final int
RETURN_ACK
private com.android.internal.telephony.cdma.sms.SmsEnvelope
mEnvelope
private com.android.internal.telephony.cdma.sms.BearerData
mBearerData
Constructors Summary
Methods Summary
public static com.android.internal.telephony.GsmAlphabet.TextEncodingDetailscalculateLength(java.lang.CharSequence messageBody, boolean use7bitOnly, boolean isEntireMsg)
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
param
isEntireMsg indicates if this is entire msg or a segment in multipart msg
return
TextEncodingDetails

        CharSequence newMsgBody = null;
        Resources r = Resources.getSystem();
        if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
            newMsgBody  = Sms7BitEncodingTranslator.translate(messageBody);
        }
        if (TextUtils.isEmpty(newMsgBody)) {
            newMsgBody = messageBody;
        }
        return BearerData.calcTextEncodingDetails(newMsgBody, use7bitOnly, isEntireMsg);
    
private byteconvertDtmfToAscii(byte dtmfDigit)
Converts a 4-Bit DTMF encoded symbol from the calling address number to ASCII character

        byte asciiDigit;

        switch (dtmfDigit) {
        case  0: asciiDigit = 68; break; // 'D'
        case  1: asciiDigit = 49; break; // '1'
        case  2: asciiDigit = 50; break; // '2'
        case  3: asciiDigit = 51; break; // '3'
        case  4: asciiDigit = 52; break; // '4'
        case  5: asciiDigit = 53; break; // '5'
        case  6: asciiDigit = 54; break; // '6'
        case  7: asciiDigit = 55; break; // '7'
        case  8: asciiDigit = 56; break; // '8'
        case  9: asciiDigit = 57; break; // '9'
        case 10: asciiDigit = 48; break; // '0'
        case 11: asciiDigit = 42; break; // '*'
        case 12: asciiDigit = 35; break; // '#'
        case 13: asciiDigit = 65; break; // 'A'
        case 14: asciiDigit = 66; break; // 'B'
        case 15: asciiDigit = 67; break; // 'C'
        default:
            asciiDigit = 32; // Invalid DTMF code
            break;
        }

        return asciiDigit;
    
public static com.android.internal.telephony.cdma.SmsMessagecreateFromEfRecord(int index, byte[] data)
Create an SmsMessage from an SMS EF record.

param
index Index of SMS record. This should be index in ArrayList returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1.
param
data Record data.
return
An SmsMessage representing the record.
hide

        try {
            SmsMessage msg = new SmsMessage();

            msg.mIndexOnIcc = index;

            // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT,
            // or STORED_UNSENT
            // See 3GPP2 C.S0023 3.4.27
            if ((data[0] & 1) == 0) {
                Rlog.w(LOG_TAG, "SMS parsing failed: Trying to parse a free record");
                return null;
            } else {
                msg.mStatusOnIcc = data[0] & 0x07;
            }

            // Second byte is the MSG_LEN, length of the message
            // See 3GPP2 C.S0023 3.4.27
            int size = data[1];

            // Note: Data may include trailing FF's.  That's OK; message
            // should still parse correctly.
            byte[] pdu = new byte[size];
            System.arraycopy(data, 2, pdu, 0, size);
            // the message has to be parsed before it can be displayed
            // see gsm.SmsMessage
            msg.parsePduFromEfRecord(pdu);
            return msg;
        } catch (RuntimeException ex) {
            Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
            return null;
        }

    
public static com.android.internal.telephony.cdma.SmsMessagecreateFromPdu(byte[] pdu)
Create an SmsMessage from a raw PDU. Note: In CDMA the PDU is just a byte representation of the received Sms.


          
    

                              
         
        SmsMessage msg = new SmsMessage();

        try {
            msg.parsePdu(pdu);
            return msg;
        } catch (RuntimeException ex) {
            Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
            return null;
        } catch (OutOfMemoryError e) {
            Log.e(LOG_TAG, "SMS PDU parsing failed with out of memory: ", e);
            return null;
        }
    
private voidcreatePdu()
Creates byte array (pseudo pdu) from SMS object. Note: Do not call this method more than once per object!

        SmsEnvelope env = mEnvelope;
        CdmaSmsAddress addr = env.origAddress;
        ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));

        try {
            dos.writeInt(env.messageType);
            dos.writeInt(env.teleService);
            dos.writeInt(env.serviceCategory);

            dos.writeByte(addr.digitMode);
            dos.writeByte(addr.numberMode);
            dos.writeByte(addr.ton);
            dos.writeByte(addr.numberPlan);
            dos.writeByte(addr.numberOfDigits);
            dos.write(addr.origBytes, 0, addr.origBytes.length); // digits

            dos.writeInt(env.bearerReply);
            // CauseCode values:
            dos.writeByte(env.replySeqNo);
            dos.writeByte(env.errorClass);
            dos.writeByte(env.causeCode);
            //encoded BearerData:
            dos.writeInt(env.bearerData.length);
            dos.write(env.bearerData, 0, env.bearerData.length);
            dos.close();

            /**
             * TODO(cleanup) -- The mPdu field is managed in
             * a fragile manner, and it would be much nicer if
             * accessing the serialized representation used a less
             * fragile mechanism.  Maybe the getPdu method could
             * generate a representation if there was not yet one?
             */

            mPdu = baos.toByteArray();
        } catch (IOException ex) {
            Rlog.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex);
        }
    
byte[]getIncomingSmsFingerprint()
Returns a byte array that can be use to uniquely identify a received SMS message. C.S0015-B 4.3.1.6 Unique Message Identification.

return
byte array uniquely identifying the message.
hide

        ByteArrayOutputStream output = new ByteArrayOutputStream();

        output.write(mEnvelope.serviceCategory);
        output.write(mEnvelope.teleService);
        output.write(mEnvelope.origAddress.origBytes, 0, mEnvelope.origAddress.origBytes.length);
        output.write(mEnvelope.bearerData, 0, mEnvelope.bearerData.length);
        output.write(mEnvelope.origSubaddress.origBytes, 0,
                mEnvelope.origSubaddress.origBytes.length);

        return output.toByteArray();
    
public SmsConstants.MessageClassgetMessageClass()
{@inheritDoc}

        if (BearerData.DISPLAY_MODE_IMMEDIATE == mBearerData.displayMode ) {
            return SmsConstants.MessageClass.CLASS_0;
        } else {
            return SmsConstants.MessageClass.UNKNOWN;
        }
    
intgetMessageType()
Returns the message type of the message.

return
the message type: {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_POINT_TO_POINT}, {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_BROADCAST}, {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_ACKNOWLEDGE},

        // NOTE: mEnvelope.messageType is not set correctly for cell broadcasts with some RILs.
        // Use the service category parameter to detect CMAS and other cell broadcast messages.
        if (mEnvelope.serviceCategory != 0) {
            return SmsEnvelope.MESSAGE_TYPE_BROADCAST;
        } else {
            return SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
        }
    
static synchronized intgetNextMessageId()
Calculate the next message id, starting at 1 and iteratively incrementing within the range 1..65535 remembering the state via a persistent system property. (See C.S0015-B, v2.0, 4.3.1.5) Since this routine is expected to be accessed via via binder-call, and hence should be thread-safe, it has been synchronized.

        // Testing and dialog with partners has indicated that
        // msgId==0 is (sometimes?) treated specially by lower levels.
        // Specifically, the ID is not preserved for delivery ACKs.
        // Hence, avoid 0 -- constraining the range to 1..65535.
        int msgId = SystemProperties.getInt(TelephonyProperties.PROPERTY_CDMA_MSG_ID, 1);
        String nextMsgId = Integer.toString((msgId % 0xFFFF) + 1);
        SystemProperties.set(TelephonyProperties.PROPERTY_CDMA_MSG_ID, nextMsgId);
        if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
            Rlog.d(LOG_TAG, "next " + TelephonyProperties.PROPERTY_CDMA_MSG_ID + " = " + nextMsgId);
            Rlog.d(LOG_TAG, "readback gets " +
                    SystemProperties.get(TelephonyProperties.PROPERTY_CDMA_MSG_ID));
        }
        return msgId;
    
intgetNumOfVoicemails()
This function shall be called to get the number of voicemails.

hide

        return mBearerData.numberOfMessages;
    
public intgetProtocolIdentifier()
Note: This function is a GSM specific functionality which is not supported in CDMA mode.

        Rlog.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode.");
        // (3GPP TS 23.040): "no interworking, but SME to SME protocol":
        return 0;
    
public java.util.ArrayListgetSmsCbProgramData()
Returns the list of service category program data, if present.

return
a list of CdmaSmsCbProgramData objects, or null if not present
hide

        return mBearerData.serviceCategoryProgramData;
    
public intgetStatus()
Returns the status for a previously submitted message. For not interfering with status codes from GSM, this status code is shifted to the bits 31-16.

        return (status << 16);
    
public static com.android.internal.telephony.cdma.SmsMessage$SubmitPdugetSubmitPdu(java.lang.String scAddr, java.lang.String destAddr, java.lang.String message, boolean statusReportRequested, com.android.internal.telephony.SmsHeader smsHeader)
Get an SMS-SUBMIT PDU for a destination address and a message

param
scAddr Service Centre address. Null means use default.
param
destAddr Address of the recipient.
param
message String representation of the message payload.
param
statusReportRequested Indicates whether a report is requested for this message.
param
smsHeader Array containing the data for the User Data Header, preceded by the Element Identifiers.
return
a SubmitPdu containing the encoded SC address, if applicable, and the encoded message. Returns null on encode error.
hide


        /**
         * TODO(cleanup): Do we really want silent failure like this?
         * Would it not be much more reasonable to make sure we don't
         * call this function if we really want nothing done?
         */
        if (message == null || destAddr == null) {
            return null;
        }

        UserData uData = new UserData();
        uData.payloadStr = message;
        uData.userDataHeader = smsHeader;
        return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
    
public static com.android.internal.telephony.cdma.SmsMessage$SubmitPdugetSubmitPdu(java.lang.String scAddr, java.lang.String destAddr, int destPort, byte[] data, boolean statusReportRequested)
Get an SMS-SUBMIT PDU for a data message to a destination address and port.

param
scAddr Service Centre address. null == use default
param
destAddr the address of the destination for the message
param
destPort the port to deliver the message to at the destination
param
data the data for the message
return
a SubmitPdu containing the encoded SC address, if applicable, and the encoded message. Returns null on encode error.


        /**
         * TODO(cleanup): this is not a general-purpose SMS creation
         * method, but rather something specialized to messages
         * containing OCTET encoded (meaning non-human-readable) user
         * data.  The name should reflect that, and not just overload.
         */

        SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
        portAddrs.destPort = destPort;
        portAddrs.origPort = 0;
        portAddrs.areEightBits = false;

        SmsHeader smsHeader = new SmsHeader();
        smsHeader.portAddrs = portAddrs;

        UserData uData = new UserData();
        uData.userDataHeader = smsHeader;
        uData.msgEncoding = UserData.ENCODING_OCTET;
        uData.msgEncodingSet = true;
        uData.payload = data;

        return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
    
public static com.android.internal.telephony.cdma.SmsMessage$SubmitPdugetSubmitPdu(java.lang.String destAddr, com.android.internal.telephony.cdma.sms.UserData userData, boolean statusReportRequested)
Get an SMS-SUBMIT PDU for a data message to a destination address & port

param
destAddr the address of the destination for the message
param
userData the data for the message
param
statusReportRequested Indicates whether a report is requested for this message.
return
a SubmitPdu containing the encoded SC address, if applicable, and the encoded message. Returns null on encode error.

        return privateGetSubmitPdu(destAddr, statusReportRequested, userData);
    
public static intgetTPLayerLengthForPDU(java.lang.String pdu)
Note: This function is a GSM specific functionality which is not supported in CDMA mode.

        Rlog.w(LOG_TAG, "getTPLayerLengthForPDU: is not supported in CDMA mode.");
        return 0;
    
intgetTeleService()
Returns the teleservice type of the message.

return
the teleservice: {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET}, {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WMT}, {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WEMT}, {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN}, {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP}

        return mEnvelope.teleService;
    
public booleanisCphsMwiMessage()
{@inheritDoc} Note: This function is a GSM specific functionality which is not supported in CDMA mode.

        Rlog.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode.");
        return false;
    
public booleanisMWIClearMessage()
{@inheritDoc}

        return ((mBearerData != null) && (mBearerData.numberOfMessages == 0));
    
public booleanisMWISetMessage()
{@inheritDoc}

        return ((mBearerData != null) && (mBearerData.numberOfMessages > 0));
    
public booleanisMwiDontStore()
{@inheritDoc}

        return ((mBearerData != null) &&
                (mBearerData.numberOfMessages > 0) &&
                (mBearerData.userData == null));
    
public booleanisReplace()
Note: This function is a GSM specific functionality which is not supported in CDMA mode.

        Rlog.w(LOG_TAG, "isReplace: is not supported in CDMA mode.");
        return false;
    
public booleanisReplyPathPresent()
Note: This function is a GSM specific functionality which is not supported in CDMA mode.

        Rlog.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode.");
        return false;
    
public booleanisStatusReportMessage()
Return true iff the bearer data message type is DELIVERY_ACK.

        return (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK);
    
public static com.android.internal.telephony.cdma.SmsMessagenewFromParcel(android.os.Parcel p)
Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp. Note: Only primitive fields are set.

        // Note: Parcel.readByte actually reads one Int and masks to byte
        SmsMessage msg = new SmsMessage();
        SmsEnvelope env = new SmsEnvelope();
        CdmaSmsAddress addr = new CdmaSmsAddress();
        CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
        byte[] data;
        byte count;
        int countInt;
        int addressDigitMode;

        //currently not supported by the modem-lib: env.mMessageType
        env.teleService = p.readInt(); //p_cur->uTeleserviceID

        if (0 != p.readByte()) { //p_cur->bIsServicePresent
            env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
        }
        else {
            if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
                // assume type ACK
                env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
            } else {
                env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
            }
        }
        env.serviceCategory = p.readInt(); //p_cur->uServicecategory

        // address
        addressDigitMode = p.readInt();
        addr.digitMode = (byte) (0xFF & addressDigitMode); //p_cur->sAddress.digit_mode
        addr.numberMode = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_mode
        addr.ton = p.readInt(); //p_cur->sAddress.number_type
        addr.numberPlan = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_plan
        count = p.readByte(); //p_cur->sAddress.number_of_digits
        addr.numberOfDigits = count;
        data = new byte[count];
        //p_cur->sAddress.digits[digitCount]
        for (int index=0; index < count; index++) {
            data[index] = p.readByte();

            // convert the value if it is 4-bit DTMF to 8 bit
            if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
                data[index] = msg.convertDtmfToAscii(data[index]);
            }
        }

        addr.origBytes = data;

        subaddr.type = p.readInt(); // p_cur->sSubAddress.subaddressType
        subaddr.odd = p.readByte();     // p_cur->sSubAddress.odd
        count = p.readByte();           // p_cur->sSubAddress.number_of_digits

        if (count < 0) {
            count = 0;
        }

        // p_cur->sSubAddress.digits[digitCount] :

        data = new byte[count];

        for (int index = 0; index < count; ++index) {
            data[index] = p.readByte();
        }

        subaddr.origBytes = data;

        /* currently not supported by the modem-lib:
            env.bearerReply
            env.replySeqNo
            env.errorClass
            env.causeCode
        */

        // bearer data
        countInt = p.readInt(); //p_cur->uBearerDataLen
        if (countInt < 0) {
            countInt = 0;
        }

        data = new byte[countInt];
        for (int index=0; index < countInt; index++) {
            data[index] = p.readByte();
        }
        // BD gets further decoded when accessed in SMSDispatcher
        env.bearerData = data;

        // link the the filled objects to the SMS
        env.origAddress = addr;
        env.origSubaddress = subaddr;
        msg.mOriginatingAddress = addr;
        msg.mEnvelope = env;

        // create byte stream representation for transportation through the layers.
        msg.createPdu();

        return msg;
    
android.telephony.SmsCbMessageparseBroadcastSms()
Parses a broadcast SMS, possibly containing a CMAS alert.

        BearerData bData = BearerData.decode(mEnvelope.bearerData, mEnvelope.serviceCategory);
        if (bData == null) {
            Rlog.w(LOG_TAG, "BearerData.decode() returned null");
            return null;
        }

        if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
            Rlog.d(LOG_TAG, "MT raw BearerData = " + HexDump.toHexString(mEnvelope.bearerData));
        }

        String plmn = TelephonyManager.getDefault().getNetworkOperator();
        SmsCbLocation location = new SmsCbLocation(plmn);

        return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP2,
                SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, bData.messageId, location,
                mEnvelope.serviceCategory, bData.getLanguage(), bData.userData.payloadStr,
                bData.priority, null, bData.cmasWarningInfo);
    
private voidparsePdu(byte[] pdu)
Decodes pdu to an empty SMS object. In the CDMA case the pdu is just an internal byte stream representation of the SMS Java-object.

see
#createPdu()

        ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
        DataInputStream dis = new DataInputStream(bais);
        int length;
        int bearerDataLength;
        SmsEnvelope env = new SmsEnvelope();
        CdmaSmsAddress addr = new CdmaSmsAddress();

        try {
            env.messageType = dis.readInt();
            env.teleService = dis.readInt();
            env.serviceCategory = dis.readInt();

            addr.digitMode = dis.readByte();
            addr.numberMode = dis.readByte();
            addr.ton = dis.readByte();
            addr.numberPlan = dis.readByte();

            length = dis.readUnsignedByte();
            addr.numberOfDigits = length;

            // sanity check on the length
            if (length > pdu.length) {
                throw new RuntimeException(
                        "createFromPdu: Invalid pdu, addr.numberOfDigits " + length
                        + " > pdu len " + pdu.length);
            }
            addr.origBytes = new byte[length];
            dis.read(addr.origBytes, 0, length); // digits

            env.bearerReply = dis.readInt();
            // CauseCode values:
            env.replySeqNo = dis.readByte();
            env.errorClass = dis.readByte();
            env.causeCode = dis.readByte();

            //encoded BearerData:
            bearerDataLength = dis.readInt();
            // sanity check on the length
            if (bearerDataLength > pdu.length) {
                throw new RuntimeException(
                        "createFromPdu: Invalid pdu, bearerDataLength " + bearerDataLength
                        + " > pdu len " + pdu.length);
            }
            env.bearerData = new byte[bearerDataLength];
            dis.read(env.bearerData, 0, bearerDataLength);
            dis.close();
        } catch (IOException ex) {
            throw new RuntimeException(
                    "createFromPdu: conversion from byte array to object failed: " + ex, ex);
        } catch (Exception ex) {
            Rlog.e(LOG_TAG, "createFromPdu: conversion from byte array to object failed: " + ex);
        }

        // link the filled objects to this SMS
        mOriginatingAddress = addr;
        env.origAddress = addr;
        mEnvelope = env;
        mPdu = pdu;

        parseSms();
    
private voidparsePduFromEfRecord(byte[] pdu)
Decodes 3GPP2 sms stored in CSIM/RUIM cards As per 3GPP2 C.S0015-0

        ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
        DataInputStream dis = new DataInputStream(bais);
        SmsEnvelope env = new SmsEnvelope();
        CdmaSmsAddress addr = new CdmaSmsAddress();
        CdmaSmsSubaddress subAddr = new CdmaSmsSubaddress();

        try {
            env.messageType = dis.readByte();

            while (dis.available() > 0) {
                int parameterId = dis.readByte();
                int parameterLen = dis.readUnsignedByte();
                byte[] parameterData = new byte[parameterLen];

                switch (parameterId) {
                    case TELESERVICE_IDENTIFIER:
                        /*
                         * 16 bit parameter that identifies which upper layer
                         * service access point is sending or should receive
                         * this message
                         */
                        env.teleService = dis.readUnsignedShort();
                        Rlog.i(LOG_TAG, "teleservice = " + env.teleService);
                        break;
                    case SERVICE_CATEGORY:
                        /*
                         * 16 bit parameter that identifies type of service as
                         * in 3GPP2 C.S0015-0 Table 3.4.3.2-1
                         */
                        env.serviceCategory = dis.readUnsignedShort();
                        break;
                    case ORIGINATING_ADDRESS:
                    case DESTINATION_ADDRESS:
                        dis.read(parameterData, 0, parameterLen);
                        BitwiseInputStream addrBis = new BitwiseInputStream(parameterData);
                        addr.digitMode = addrBis.read(1);
                        addr.numberMode = addrBis.read(1);
                        int numberType = 0;
                        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
                            numberType = addrBis.read(3);
                            addr.ton = numberType;

                            if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK)
                                addr.numberPlan = addrBis.read(4);
                        }

                        addr.numberOfDigits = addrBis.read(8);

                        byte[] data = new byte[addr.numberOfDigits];
                        byte b = 0x00;

                        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
                            /* As per 3GPP2 C.S0005-0 Table 2.7.1.3.2.4-4 */
                            for (int index = 0; index < addr.numberOfDigits; index++) {
                                b = (byte) (0xF & addrBis.read(4));
                                // convert the value if it is 4-bit DTMF to 8
                                // bit
                                data[index] = convertDtmfToAscii(b);
                            }
                        } else if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
                            if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK) {
                                for (int index = 0; index < addr.numberOfDigits; index++) {
                                    b = (byte) (0xFF & addrBis.read(8));
                                    data[index] = b;
                                }

                            } else if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK) {
                                if (numberType == 2)
                                    Rlog.e(LOG_TAG, "TODO: Originating Addr is email id");
                                else
                                    Rlog.e(LOG_TAG,
                                          "TODO: Originating Addr is data network address");
                            } else {
                                Rlog.e(LOG_TAG, "Originating Addr is of incorrect type");
                            }
                        } else {
                            Rlog.e(LOG_TAG, "Incorrect Digit mode");
                        }
                        addr.origBytes = data;
                        Rlog.i(LOG_TAG, "Originating Addr=" + addr.toString());
                        break;
                    case ORIGINATING_SUB_ADDRESS:
                    case DESTINATION_SUB_ADDRESS:
                        dis.read(parameterData, 0, parameterLen);
                        BitwiseInputStream subAddrBis = new BitwiseInputStream(parameterData);
                        subAddr.type = subAddrBis.read(3);
                        subAddr.odd = subAddrBis.readByteArray(1)[0];
                        int subAddrLen = subAddrBis.read(8);
                        byte[] subdata = new byte[subAddrLen];
                        for (int index = 0; index < subAddrLen; index++) {
                            b = (byte) (0xFF & subAddrBis.read(4));
                            // convert the value if it is 4-bit DTMF to 8 bit
                            subdata[index] = convertDtmfToAscii(b);
                        }
                        subAddr.origBytes = subdata;
                        break;
                    case BEARER_REPLY_OPTION:
                        dis.read(parameterData, 0, parameterLen);
                        BitwiseInputStream replyOptBis = new BitwiseInputStream(parameterData);
                        env.bearerReply = replyOptBis.read(6);
                        break;
                    case CAUSE_CODES:
                        dis.read(parameterData, 0, parameterLen);
                        BitwiseInputStream ccBis = new BitwiseInputStream(parameterData);
                        env.replySeqNo = ccBis.readByteArray(6)[0];
                        env.errorClass = ccBis.readByteArray(2)[0];
                        if (env.errorClass != 0x00)
                            env.causeCode = ccBis.readByteArray(8)[0];
                        break;
                    case BEARER_DATA:
                        dis.read(parameterData, 0, parameterLen);
                        env.bearerData = parameterData;
                        break;
                    default:
                        throw new Exception("unsupported parameterId (" + parameterId + ")");
                }
            }
            bais.close();
            dis.close();
        } catch (Exception ex) {
            Rlog.e(LOG_TAG, "parsePduFromEfRecord: conversion from pdu to SmsMessage failed" + ex);
        }

        // link the filled objects to this SMS
        mOriginatingAddress = addr;
        env.origAddress = addr;
        env.origSubaddress = subAddr;
        mEnvelope = env;
        mPdu = pdu;

        parseSms();
    
protected voidparseSms()
Parses a SMS message from its BearerData stream. (mobile-terminated only)

        // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6
        // It contains only an 8-bit number with the number of messages waiting
        if (mEnvelope.teleService == SmsEnvelope.TELESERVICE_MWI) {
            mBearerData = new BearerData();
            if (mEnvelope.bearerData != null) {
                mBearerData.numberOfMessages = 0x000000FF & mEnvelope.bearerData[0];
            }
            if (VDBG) {
                Rlog.d(LOG_TAG, "parseSms: get MWI " +
                      Integer.toString(mBearerData.numberOfMessages));
            }
            return;
        }
        mBearerData = BearerData.decode(mEnvelope.bearerData);
        if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
            Rlog.d(LOG_TAG, "MT raw BearerData = '" +
                      HexDump.toHexString(mEnvelope.bearerData) + "'");
            Rlog.d(LOG_TAG, "MT (decoded) BearerData = " + mBearerData);
        }
        mMessageRef = mBearerData.messageId;
        if (mBearerData.userData != null) {
            mUserData = mBearerData.userData.payload;
            mUserDataHeader = mBearerData.userData.userDataHeader;
            mMessageBody = mBearerData.userData.payloadStr;
        }

        if (mOriginatingAddress != null) {
            mOriginatingAddress.address = new String(mOriginatingAddress.origBytes);
            if (mOriginatingAddress.ton == CdmaSmsAddress.TON_INTERNATIONAL_OR_IP) {
                if (mOriginatingAddress.address.charAt(0) != '+") {
                    mOriginatingAddress.address = "+" + mOriginatingAddress.address;
                }
            }
            if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: "
                    + mOriginatingAddress.address);
        }

        if (mBearerData.msgCenterTimeStamp != null) {
            mScTimeMillis = mBearerData.msgCenterTimeStamp.toMillis(true);
        }

        if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis);

        // Message Type (See 3GPP2 C.S0015-B, v2, 4.5.1)
        if (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) {
            // The BearerData MsgStatus subparameter should only be
            // included for DELIVERY_ACK messages.  If it occurred for
            // other messages, it would be unclear what the status
            // being reported refers to.  The MsgStatus subparameter
            // is primarily useful to indicate error conditions -- a
            // message without this subparameter is assumed to
            // indicate successful delivery (status == 0).
            if (! mBearerData.messageStatusSet) {
                Rlog.d(LOG_TAG, "DELIVERY_ACK message without msgStatus (" +
                        (mUserData == null ? "also missing" : "does have") +
                        " userData).");
                status = 0;
            } else {
                status = mBearerData.errorClass << 8;
                status |= mBearerData.messageStatus;
            }
        } else if (mBearerData.messageType != BearerData.MESSAGE_TYPE_DELIVER) {
            throw new RuntimeException("Unsupported message type: " + mBearerData.messageType);
        }

        if (mMessageBody != null) {
            if (VDBG) Rlog.v(LOG_TAG, "SMS message body: '" + mMessageBody + "'");
            parseMessageBody();
        } else if ((mUserData != null) && VDBG) {
            Rlog.v(LOG_TAG, "SMS payload: '" + IccUtils.bytesToHexString(mUserData) + "'");
        }
    
private static com.android.internal.telephony.cdma.SmsMessage$SubmitPduprivateGetSubmitPdu(java.lang.String destAddrStr, boolean statusReportRequested, com.android.internal.telephony.cdma.sms.UserData userData)
Creates BearerData and Envelope from parameters for a Submit SMS.

return
byte stream for SubmitPdu.


        /**
         * TODO(cleanup): give this function a more meaningful name.
         */

        /**
         * TODO(cleanup): Make returning null from the getSubmitPdu
         * variations meaningful -- clean up the error feedback
         * mechanism, and avoid null pointer exceptions.
         */

        /**
         * North America Plus Code :
         * Convert + code to 011 and dial out for international SMS
         */
        CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
                PhoneNumberUtils.cdmaCheckAndProcessPlusCodeForSms(destAddrStr));
        if (destAddr == null) return null;

        BearerData bearerData = new BearerData();
        bearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;

        bearerData.messageId = getNextMessageId();

        bearerData.deliveryAckReq = statusReportRequested;
        bearerData.userAckReq = false;
        bearerData.readAckReq = false;
        bearerData.reportReq = false;

        bearerData.userData = userData;

        byte[] encodedBearerData = BearerData.encode(bearerData);
        if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
            Rlog.d(LOG_TAG, "MO (encoded) BearerData = " + bearerData);
            Rlog.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'");
        }
        if (encodedBearerData == null) return null;

        int teleservice = bearerData.hasUserDataHeader ?
                SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;

        SmsEnvelope envelope = new SmsEnvelope();
        envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
        envelope.teleService = teleservice;
        envelope.destAddress = destAddr;
        envelope.bearerReply = RETURN_ACK;
        envelope.bearerData = encodedBearerData;

        /**
         * TODO(cleanup): envelope looks to be a pointless class, get
         * rid of it.  Also -- most of the envelope fields set here
         * are ignored, why?
         */

        try {
            /**
             * TODO(cleanup): reference a spec and get rid of the ugly comments
             */
            ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeInt(envelope.teleService);
            dos.writeInt(0); //servicePresent
            dos.writeInt(0); //serviceCategory
            dos.write(destAddr.digitMode);
            dos.write(destAddr.numberMode);
            dos.write(destAddr.ton); // number_type
            dos.write(destAddr.numberPlan);
            dos.write(destAddr.numberOfDigits);
            dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
            // Subaddress is not supported.
            dos.write(0); //subaddressType
            dos.write(0); //subaddr_odd
            dos.write(0); //subaddr_nbr_of_digits
            dos.write(encodedBearerData.length);
            dos.write(encodedBearerData, 0, encodedBearerData.length);
            dos.close();

            SubmitPdu pdu = new SubmitPdu();
            pdu.encodedMessage = baos.toByteArray();
            pdu.encodedScAddress = null;
            return pdu;
        } catch(IOException ex) {
            Rlog.e(LOG_TAG, "creating SubmitPdu failed: " + ex);
        }
        return null;