FileDocCategorySizeDatePackage
SmsMessage.javaAPI DocAndroid 5.1 API31989Thu Mar 12 22:22:54 GMT 2015android.telephony

SmsMessage

public class SmsMessage extends Object
A Short Message Service message.
see
android.provider.Telephony.Sms.Intents#getMessagesFromIntent

Fields Summary
private static final String
LOG_TAG
public static final int
ENCODING_UNKNOWN
User data text encoding code unit size
public static final int
ENCODING_7BIT
public static final int
ENCODING_8BIT
public static final int
ENCODING_16BIT
public static final int
ENCODING_KSC5601
public static final int
MAX_USER_DATA_BYTES
The maximum number of payload bytes per message
public static final int
MAX_USER_DATA_BYTES_WITH_HEADER
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.
public static final int
MAX_USER_DATA_SEPTETS
The maximum number of payload septets per message
public static final int
MAX_USER_DATA_SEPTETS_WITH_HEADER
The maximum number of payload septets per message if a user data header is present. This assumes the header only contains the CONCATENATED_8_BIT_REFERENCE element.
public static final String
FORMAT_3GPP
Indicates a 3GPP format SMS message.
public static final String
FORMAT_3GPP2
Indicates a 3GPP2 format SMS message.
public com.android.internal.telephony.SmsMessageBase
mWrappedSmsMessage
Contains actual SmsMessage. Only public for debugging and for framework layer.
private int
mSubId
Indicates the subId
private static NoEmsSupportConfig[]
mNoEmsSupportConfigList
private static boolean
mIsNoEmsSupportConfigListLoaded
Constructors Summary
private SmsMessage(com.android.internal.telephony.SmsMessageBase smb)

        mWrappedSmsMessage = smb;
    
Methods Summary
public static int[]calculateLength(java.lang.CharSequence msgBody, boolean use7bitOnly)
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 if true, characters that are not part of the radio-specific 7-bit encoding are counted as single 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 an indicator of the encoding code unit size (see the ENCODING_* definitions in SmsConstants)

        // this function is for MO SMS
        TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?
            com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly,
                    true) :
            com.android.internal.telephony.gsm.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;
    
public static int[]calculateLength(java.lang.String messageBody, boolean use7bitOnly)
Calculates the number of SMS's required to encode the message body and the number of characters remaining until the next message, given the current encoding.

param
messageBody the message to encode
param
use7bitOnly if true, characters that are not part of the radio specific (GSM / CDMA) alphabet encoding are converted to as a single space characters. If false, a messageBody containing non-GSM or non-CDMA alphabet characters are encoded using 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 calculateLength((CharSequence)messageBody, use7bitOnly);
    
public static android.telephony.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 SmsManager.getAllMessagesFromSim + 1.
param
data Record data.
return
An SmsMessage representing the record.
hide

        SmsMessageBase wrappedMessage;

        if (isCdmaVoice()) {
            wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
                    index, data);
        } else {
            wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
                    index, data);
        }

        return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null;
    
public static android.telephony.SmsMessagecreateFromPdu(byte[] pdu)
Create an SmsMessage from a raw PDU.

This method will soon be deprecated and all applications which handle incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast intent must now pass the new {@code format} String extra from the intent into the new method {@code createFromPdu(byte[], String)} which takes an extra format parameter. This is required in order to correctly decode the PDU on devices that require support for both 3GPP and 3GPP2 formats at the same time, such as dual-mode GSM/CDMA and CDMA/LTE phones. Guess format based on Voice technology first, if it fails use other format.

         SmsMessage message = null;

        // cdma(3gpp2) vs gsm(3gpp) format info was not given,
        // guess from active voice phone type
        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
        String format = (PHONE_TYPE_CDMA == activePhone) ?
                SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP;
        message = createFromPdu(pdu, format);

        if (null == message || null == message.mWrappedSmsMessage) {
            // decoding pdu failed based on activePhone type, must be other format
            format = (PHONE_TYPE_CDMA == activePhone) ?
                    SmsConstants.FORMAT_3GPP : SmsConstants.FORMAT_3GPP2;
            message = createFromPdu(pdu, format);
        }
        return message;
    
public static android.telephony.SmsMessagecreateFromPdu(byte[] pdu, java.lang.String format)
Create an SmsMessage from a raw PDU with the specified message format. The message format is passed in the {@code SMS_RECEIVED_ACTION} as the {@code format} String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format or "3gpp2" for CDMA/LTE messages in 3GPP2 format.

param
pdu the message PDU from the SMS_RECEIVED_ACTION intent
param
format the format extra from the SMS_RECEIVED_ACTION intent
hide
pending API council approval

        SmsMessageBase wrappedMessage;

        if (SmsConstants.FORMAT_3GPP2.equals(format)) {
            wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
        } else if (SmsConstants.FORMAT_3GPP.equals(format)) {
            wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
        } else {
            Rlog.e(LOG_TAG, "createFromPdu(): unsupported message format " + format);
            return null;
        }

        return new SmsMessage(wrappedMessage);
    
public static java.util.ArrayListfragmentText(java.lang.String text)
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 ArrayList of strings that, in order, comprise the original msg text
hide

        // This function is for MO SMS
        TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?
            com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false, true) :
            com.android.internal.telephony.gsm.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.codeUnitSize == SmsConstants.ENCODING_7BIT) {
            int udhLength;
            if (ted.languageTable != 0 && ted.languageShiftTable != 0) {
                udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;
            } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {
                udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;
            } else {
                udhLength = 0;
            }

            if (ted.msgCount > 1) {
                udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE;
            }

            if (udhLength != 0) {
                udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;
            }

            limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength;
        } else {
            if (ted.msgCount > 1) {
                limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
                // If EMS is not supported, break down EMS into single segment SMS
                // and add page info " x/y".
                // In the case of UCS2 encoding, 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).
                // Make sure total number of segments is less than 10.
                if (!hasEmsSupport() && ted.msgCount < 10) {
                    limit -= 2;
                }
            } else {
                limit = SmsConstants.MAX_USER_DATA_BYTES;
            }
        }

        String newMsgBody = null;
        Resources r = Resources.getSystem();
        if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
            newMsgBody  = Sms7BitEncodingTranslator.translate(text);
        }
        if (TextUtils.isEmpty(newMsgBody)) {
            newMsgBody = text;
        }
        int pos = 0;  // Index in code units.
        int textLen = newMsgBody.length();
        ArrayList<String> result = new ArrayList<String>(ted.msgCount);
        while (pos < textLen) {
            int nextPos = 0;  // Counts code units.
            if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
                if (useCdmaFormatForMoSms() && ted.msgCount == 1) {
                    // For a singleton CDMA message, the encoding must be ASCII...
                    nextPos = pos + Math.min(limit, textLen - pos);
                } else {
                    // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).
                    nextPos = GsmAlphabet.findGsmSeptetLimitIndex(newMsgBody, pos, limit,
                            ted.languageTable, ted.languageShiftTable);
                }
            } else {  // Assume unicode.
                nextPos = pos + Math.min(limit / 2, textLen - pos);
            }
            if ((nextPos <= pos) || (nextPos > textLen)) {
                Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
                          nextPos + " >= " + textLen + ")");
                break;
            }
            result.add(newMsgBody.substring(pos, nextPos));
            pos = nextPos;
        }
        return result;
    
public java.lang.StringgetDisplayMessageBody()
Returns the message body, or email message body if this message was from an email gateway. Returns null if message body unavailable.

        return mWrappedSmsMessage.getDisplayMessageBody();
    
public java.lang.StringgetDisplayOriginatingAddress()
Returns the originating address, or email from address if this message was from an email gateway. Returns null if originating address unavailable.

        return mWrappedSmsMessage.getDisplayOriginatingAddress();
    
public java.lang.StringgetEmailBody()

return
if isEmail() is true, body of the email sent through the gateway. null otherwise

        return mWrappedSmsMessage.getEmailBody();
    
public java.lang.StringgetEmailFrom()

return
if isEmail() is true, email from address of email sent through the gateway. null otherwise

        return mWrappedSmsMessage.getEmailFrom();
    
public intgetIndexOnIcc()
Returns the record index of the message on the ICC (1-based index).

return
the record index of the message on the ICC, or -1 if this SmsMessage was not created from a ICC SMS EF record.

        return mWrappedSmsMessage.getIndexOnIcc();
    
public intgetIndexOnSim()
Returns the record index of the message on the SIM (1-based index).

return
the record index of the message on the SIM, or -1 if this SmsMessage was not created from a SIM SMS EF record.
deprecated
Use getIndexOnIcc instead.

        return mWrappedSmsMessage.getIndexOnIcc();
    
public java.lang.StringgetMessageBody()
Returns the message body as a String, if it exists and is text based.

return
message body is there is one, otherwise null

        return mWrappedSmsMessage.getMessageBody();
    
public android.telephony.SmsMessage$MessageClassgetMessageClass()
Returns the class of this message.

        switch(mWrappedSmsMessage.getMessageClass()) {
            case CLASS_0: return MessageClass.CLASS_0;
            case CLASS_1: return MessageClass.CLASS_1;
            case CLASS_2: return MessageClass.CLASS_2;
            case CLASS_3: return MessageClass.CLASS_3;
            default: return MessageClass.UNKNOWN;

        }
    
public java.lang.StringgetOriginatingAddress()
Returns the originating address (sender) of this SMS message in String form or null if unavailable

        return mWrappedSmsMessage.getOriginatingAddress();
    
public byte[]getPdu()
Returns the raw PDU for the message.

return
the raw PDU for the message.

        return mWrappedSmsMessage.getPdu();
    
public intgetProtocolIdentifier()
Get protocol identifier.

        return mWrappedSmsMessage.getProtocolIdentifier();
    
public java.lang.StringgetPseudoSubject()
Unofficial convention of a subject line enclosed in parens empty string if not present

        return mWrappedSmsMessage.getPseudoSubject();
    
public java.lang.StringgetServiceCenterAddress()
Returns the address of the SMS service center that relayed this message or null if there is none.

        return mWrappedSmsMessage.getServiceCenterAddress();
    
public intgetStatus()
GSM: For an SMS-STATUS-REPORT message, this returns the status field from the status report. This field indicates the status of a previously submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a description of values. CDMA: For not interfering with status codes from GSM, the value is shifted to the bits 31-16. The value is composed of an error class (bits 25-24) and a status code (bits 23-16). Possible codes are described in C.S0015-B, v2.0, 4.5.21.

return
0 indicates the previously sent message was received. See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21 for a description of other possible values.

        return mWrappedSmsMessage.getStatus();
    
public intgetStatusOnIcc()
Returns the status of the message on the ICC (read, unread, sent, unsent).

return
the status of the message on the ICC. These are: SmsManager.STATUS_ON_ICC_FREE SmsManager.STATUS_ON_ICC_READ SmsManager.STATUS_ON_ICC_UNREAD SmsManager.STATUS_ON_ICC_SEND SmsManager.STATUS_ON_ICC_UNSENT

        return mWrappedSmsMessage.getStatusOnIcc();
    
public intgetStatusOnSim()
Returns the status of the message on the SIM (read, unread, sent, unsent).

return
the status of the message on the SIM. These are: SmsManager.STATUS_ON_SIM_FREE SmsManager.STATUS_ON_SIM_READ SmsManager.STATUS_ON_SIM_UNREAD SmsManager.STATUS_ON_SIM_SEND SmsManager.STATUS_ON_SIM_UNSENT
deprecated
Use getStatusOnIcc instead.

        return mWrappedSmsMessage.getStatusOnIcc();
    
public intgetSubId()
get Subscription information

hide

        return mSubId;
    
public static android.telephony.SmsMessage$SubmitPdugetSubmitPdu(java.lang.String scAddress, java.lang.String destinationAddress, java.lang.String message, boolean statusReportRequested)
Get an SMS-SUBMIT PDU for a destination address and a message. This method will not attempt to use any GSM national language 7 bit encodings.

param
scAddress Service Centre address. Null means use default.
return
a SubmitPdu containing the encoded SC address, if applicable, and the encoded message. Returns null on encode error.

        SubmitPduBase spb;

        if (useCdmaFormatForMoSms()) {
            spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
                    destinationAddress, message, statusReportRequested, null);
        } else {
            spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
                    destinationAddress, message, statusReportRequested);
        }

        return new SubmitPdu(spb);
    
public static android.telephony.SmsMessage$SubmitPdugetSubmitPdu(java.lang.String scAddress, java.lang.String destinationAddress, short destinationPort, byte[] data, boolean statusReportRequested)
Get an SMS-SUBMIT PDU for a data message to a destination address & port. This method will not attempt to use any GSM national language 7 bit encodings.

param
scAddress Service Centre address. null == use default
param
destinationAddress the address of the destination for the message
param
destinationPort 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.

        SubmitPduBase spb;

        if (useCdmaFormatForMoSms()) {
            spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
                    destinationAddress, destinationPort, data, statusReportRequested);
        } else {
            spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
                    destinationAddress, destinationPort, data, statusReportRequested);
        }

        return new SubmitPdu(spb);
    
public static intgetTPLayerLengthForPDU(java.lang.String pdu)
Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the length in bytes (not hex chars) less the SMSC header FIXME: This method is only used by a CTS test case that isn't run on CDMA devices. We should probably deprecate it and remove the obsolete test case.

        if (isCdmaVoice()) {
            return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu);
        } else {
            return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu);
        }
    
public longgetTimestampMillis()
Returns the service centre timestamp in currentTimeMillis() format

        return mWrappedSmsMessage.getTimestampMillis();
    
public byte[]getUserData()
returns the user data section minus the user data header if one was present.

        return mWrappedSmsMessage.getUserData();
    
public static booleanhasEmsSupport()
Decide if the carrier supports long SMS. {@hide}

        if (!isNoEmsSupportConfigListExisted()) {
            return true;
        }

        String simOperator;
        String gid;
        final long identity = Binder.clearCallingIdentity();
        try {
            simOperator = TelephonyManager.getDefault().getSimOperatorNumeric();
            gid = TelephonyManager.getDefault().getGroupIdLevel1();
        } finally {
            Binder.restoreCallingIdentity(identity);
        }

        for (NoEmsSupportConfig currentConfig : mNoEmsSupportConfigList) {
            if (simOperator.startsWith(currentConfig.mOperatorNumber) &&
                (TextUtils.isEmpty(currentConfig.mGid1) ||
                (!TextUtils.isEmpty(currentConfig.mGid1)
                && currentConfig.mGid1.equalsIgnoreCase(gid)))) {
                return false;
            }
         }
        return true;
    
private static booleanisCdmaVoice()
Determines whether or not to current phone type is cdma.

return
true if current phone type is cdma, false otherwise.

        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
        return (PHONE_TYPE_CDMA == activePhone);
    
public booleanisCphsMwiMessage()
Returns true for CPHS MWI toggle message.

return
true if this is a CPHS MWI toggle message See CPHS 4.2 section B.4.2

        return mWrappedSmsMessage.isCphsMwiMessage();
    
public booleanisEmail()
Returns true if message is an email.

return
true if this message came through an email gateway and email sender / subject / parsed body are available

        return mWrappedSmsMessage.isEmail();
    
public booleanisMWIClearMessage()
returns true if this message is a CPHS voicemail / message waiting indicator (MWI) clear message

        return mWrappedSmsMessage.isMWIClearMessage();
    
public booleanisMWISetMessage()
returns true if this message is a CPHS voicemail / message waiting indicator (MWI) set message

        return mWrappedSmsMessage.isMWISetMessage();
    
public booleanisMwiDontStore()
returns true if this message is a "Message Waiting Indication Group: Discard Message" notification and should not be stored.

        return mWrappedSmsMessage.isMwiDontStore();
    
private static booleanisNoEmsSupportConfigListExisted()


        
        if (!mIsNoEmsSupportConfigListLoaded) {
            Resources r = Resources.getSystem();
            if (r != null) {
                String[] listArray = r.getStringArray(
                        com.android.internal.R.array.no_ems_support_sim_operators);
                if ((listArray != null) && (listArray.length > 0)) {
                    mNoEmsSupportConfigList = new NoEmsSupportConfig[listArray.length];
                    for (int i=0; i<listArray.length; i++) {
                        mNoEmsSupportConfigList[i] = new NoEmsSupportConfig(listArray[i].split(";"));
                    }
                }
                mIsNoEmsSupportConfigListLoaded = true;
            }
        }

        if (mNoEmsSupportConfigList != null && mNoEmsSupportConfigList.length != 0) {
            return true;
        }

        return false;
    
public booleanisReplace()
See TS 23.040 9.2.3.9 returns true if this is a "replace short message" SMS

        return mWrappedSmsMessage.isReplace();
    
public booleanisReplyPathPresent()
Returns true iff the TP-Reply-Path bit is set in this message.

        return mWrappedSmsMessage.isReplyPathPresent();
    
public booleanisStatusReportMessage()
Return true iff the message is a SMS-STATUS-REPORT message.

        return mWrappedSmsMessage.isStatusReportMessage();
    
public static android.telephony.SmsMessagenewFromCMT(java.lang.String[] lines)
TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the +CMT unsolicited response (PDU mode, of course) +CMT: [<alpha>], Only public for debugging and for RIL {@hide}

        // received SMS in 3GPP format
        SmsMessageBase wrappedMessage =
                com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines);

        return new SmsMessage(wrappedMessage);
    
public static android.telephony.SmsMessagenewFromParcel(android.os.Parcel p)

hide

        // received SMS in 3GPP2 format
        SmsMessageBase wrappedMessage =
                com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p);

        return new SmsMessage(wrappedMessage);
    
public voidsetSubId(int subId)
set Subscription information

hide


             
        
        mSubId = subId;
    
public static booleanshouldAppendPageNumberAsPrefix()
Check where to add " x/y" in each SMS segment, begin or end. {@hide}

        if (!isNoEmsSupportConfigListExisted()) {
            return false;
        }

        String simOperator;
        String gid;
        final long identity = Binder.clearCallingIdentity();
        try {
            simOperator = TelephonyManager.getDefault().getSimOperatorNumeric();
            gid = TelephonyManager.getDefault().getGroupIdLevel1();
        } finally {
            Binder.restoreCallingIdentity(identity);
        }

        for (NoEmsSupportConfig currentConfig : mNoEmsSupportConfigList) {
            if (simOperator.startsWith(currentConfig.mOperatorNumber) &&
                (TextUtils.isEmpty(currentConfig.mGid1) ||
                (!TextUtils.isEmpty(currentConfig.mGid1)
                && currentConfig.mGid1.equalsIgnoreCase(gid)))) {
                return currentConfig.mIsPrefix;
            }
        }
        return false;
    
private static booleanuseCdmaFormatForMoSms()
Determines whether or not to use CDMA format for MO SMS. If SMS over IMS is supported, then format is based on IMS SMS format, otherwise format is based on current phone type.

return
true if Cdma format should be used for MO SMS, false otherwise.

        if (!SmsManager.getDefault().isImsSmsSupported()) {
            // use Voice technology to determine SMS format.
            return isCdmaVoice();
        }
        // IMS is registered with SMS support, check the SMS format supported
        return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));