SmsMessage.java revision cbaa45bbf2cab852b6c9c3a887e9f803d4e857ea
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.telephony; 18 19import android.os.Parcel; 20import android.telephony.Rlog; 21 22import com.android.internal.telephony.GsmAlphabet; 23import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; 24import com.android.internal.telephony.SmsConstants; 25import com.android.internal.telephony.SmsMessageBase; 26import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; 27 28import java.lang.Math; 29import java.util.ArrayList; 30import java.util.Arrays; 31 32import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; 33 34 35/** 36 * A Short Message Service message. 37 */ 38public class SmsMessage { 39 private static final String LOG_TAG = "SmsMessage"; 40 41 /** 42 * SMS Class enumeration. 43 * See TS 23.038. 44 * 45 */ 46 public enum MessageClass{ 47 UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; 48 } 49 50 /** User data text encoding code unit size */ 51 public static final int ENCODING_UNKNOWN = 0; 52 public static final int ENCODING_7BIT = 1; 53 public static final int ENCODING_8BIT = 2; 54 public static final int ENCODING_16BIT = 3; 55 /** 56 * @hide This value is not defined in global standard. Only in Korea, this is used. 57 */ 58 public static final int ENCODING_KSC5601 = 4; 59 60 /** The maximum number of payload bytes per message */ 61 public static final int MAX_USER_DATA_BYTES = 140; 62 63 /** 64 * The maximum number of payload bytes per message if a user data header 65 * is present. This assumes the header only contains the 66 * CONCATENATED_8_BIT_REFERENCE element. 67 */ 68 public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; 69 70 /** The maximum number of payload septets per message */ 71 public static final int MAX_USER_DATA_SEPTETS = 160; 72 73 /** 74 * The maximum number of payload septets per message if a user data header 75 * is present. This assumes the header only contains the 76 * CONCATENATED_8_BIT_REFERENCE element. 77 */ 78 public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; 79 80 /** 81 * Indicates a 3GPP format SMS message. 82 * @hide pending API council approval 83 */ 84 public static final String FORMAT_3GPP = "3gpp"; 85 86 /** 87 * Indicates a 3GPP2 format SMS message. 88 * @hide pending API council approval 89 */ 90 public static final String FORMAT_3GPP2 = "3gpp2"; 91 92 /** Contains actual SmsMessage. Only public for debugging and for framework layer. 93 * 94 * @hide 95 */ 96 public SmsMessageBase mWrappedSmsMessage; 97 98 public static class SubmitPdu { 99 100 public byte[] encodedScAddress; // Null if not applicable. 101 public byte[] encodedMessage; 102 103 @Override 104 public String toString() { 105 return "SubmitPdu: encodedScAddress = " 106 + Arrays.toString(encodedScAddress) 107 + ", encodedMessage = " 108 + Arrays.toString(encodedMessage); 109 } 110 111 /** 112 * @hide 113 */ 114 protected SubmitPdu(SubmitPduBase spb) { 115 this.encodedMessage = spb.encodedMessage; 116 this.encodedScAddress = spb.encodedScAddress; 117 } 118 119 } 120 121 private SmsMessage(SmsMessageBase smb) { 122 mWrappedSmsMessage = smb; 123 } 124 125 /** 126 * Create an SmsMessage from a raw PDU. 127 * 128 * <p><b>This method will soon be deprecated</b> and all applications which handle 129 * incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast 130 * intent <b>must</b> now pass the new {@code format} String extra from the intent 131 * into the new method {@code createFromPdu(byte[], String)} which takes an 132 * extra format parameter. This is required in order to correctly decode the PDU on 133 * devices that require support for both 3GPP and 3GPP2 formats at the same time, 134 * such as dual-mode GSM/CDMA and CDMA/LTE phones. 135 */ 136 public static SmsMessage createFromPdu(byte[] pdu) { 137 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 138 String format = (PHONE_TYPE_CDMA == activePhone) ? 139 SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP; 140 return createFromPdu(pdu, format); 141 } 142 143 /** 144 * Create an SmsMessage from a raw PDU with the specified message format. The 145 * message format is passed in the {@code SMS_RECEIVED_ACTION} as the {@code format} 146 * String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format 147 * or "3gpp2" for CDMA/LTE messages in 3GPP2 format. 148 * 149 * @param pdu the message PDU from the SMS_RECEIVED_ACTION intent 150 * @param format the format extra from the SMS_RECEIVED_ACTION intent 151 * @hide pending API council approval 152 */ 153 public static SmsMessage createFromPdu(byte[] pdu, String format) { 154 SmsMessageBase wrappedMessage; 155 156 if (SmsConstants.FORMAT_3GPP2.equals(format)) { 157 wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); 158 } else if (SmsConstants.FORMAT_3GPP.equals(format)) { 159 wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); 160 } else { 161 Rlog.e(LOG_TAG, "createFromPdu(): unsupported message format " + format); 162 return null; 163 } 164 165 return new SmsMessage(wrappedMessage); 166 } 167 168 /** 169 * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the 170 * +CMT unsolicited response (PDU mode, of course) 171 * +CMT: [<alpha>],<length><CR><LF><pdu> 172 * 173 * Only public for debugging and for RIL 174 * 175 * {@hide} 176 */ 177 public static SmsMessage newFromCMT(String[] lines) { 178 // received SMS in 3GPP format 179 SmsMessageBase wrappedMessage = 180 com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); 181 182 return new SmsMessage(wrappedMessage); 183 } 184 185 /** @hide */ 186 public static SmsMessage newFromParcel(Parcel p) { 187 // received SMS in 3GPP2 format 188 SmsMessageBase wrappedMessage = 189 com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); 190 191 return new SmsMessage(wrappedMessage); 192 } 193 194 /** 195 * Create an SmsMessage from an SMS EF record. 196 * 197 * @param index Index of SMS record. This should be index in ArrayList 198 * returned by SmsManager.getAllMessagesFromSim + 1. 199 * @param data Record data. 200 * @return An SmsMessage representing the record. 201 * 202 * @hide 203 */ 204 public static SmsMessage createFromEfRecord(int index, byte[] data) { 205 SmsMessageBase wrappedMessage; 206 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 207 208 if (PHONE_TYPE_CDMA == activePhone) { 209 wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( 210 index, data); 211 } else { 212 wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( 213 index, data); 214 } 215 216 return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null; 217 } 218 219 /** 220 * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the 221 * length in bytes (not hex chars) less the SMSC header 222 * 223 * FIXME: This method is only used by a CTS test case that isn't run on CDMA devices. 224 * We should probably deprecate it and remove the obsolete test case. 225 */ 226 public static int getTPLayerLengthForPDU(String pdu) { 227 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 228 229 if (PHONE_TYPE_CDMA == activePhone) { 230 return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu); 231 } else { 232 return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu); 233 } 234 } 235 236 /* 237 * TODO(cleanup): It would make some sense if the result of 238 * preprocessing a message to determine the proper encoding (i.e. 239 * the resulting data structure from calculateLength) could be 240 * passed as an argument to the actual final encoding function. 241 * This would better ensure that the logic behind size calculation 242 * actually matched the encoding. 243 */ 244 245 /** 246 * Calculates the number of SMS's required to encode the message body and 247 * the number of characters remaining until the next message. 248 * 249 * @param msgBody the message to encode 250 * @param use7bitOnly if true, characters that are not part of the 251 * radio-specific 7-bit encoding are counted as single 252 * space chars. If false, and if the messageBody contains 253 * non-7-bit encodable characters, length is calculated 254 * using a 16-bit encoding. 255 * @return an int[4] with int[0] being the number of SMS's 256 * required, int[1] the number of code units used, and 257 * int[2] is the number of code units remaining until the 258 * next message. int[3] is an indicator of the encoding 259 * code unit size (see the ENCODING_* definitions in SmsConstants) 260 */ 261 public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) { 262 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 263 TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ? 264 com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly) : 265 com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly); 266 int ret[] = new int[4]; 267 ret[0] = ted.msgCount; 268 ret[1] = ted.codeUnitCount; 269 ret[2] = ted.codeUnitsRemaining; 270 ret[3] = ted.codeUnitSize; 271 return ret; 272 } 273 274 /** 275 * Divide a message text into several fragments, none bigger than 276 * the maximum SMS message text size. 277 * 278 * @param text text, must not be null. 279 * @return an <code>ArrayList</code> of strings that, in order, 280 * comprise the original msg text 281 * 282 * @hide 283 */ 284 public static ArrayList<String> fragmentText(String text) { 285 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 286 TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ? 287 com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false) : 288 com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false); 289 290 // TODO(cleanup): The code here could be rolled into the logic 291 // below cleanly if these MAX_* constants were defined more 292 // flexibly... 293 294 int limit; 295 if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) { 296 int udhLength; 297 if (ted.languageTable != 0 && ted.languageShiftTable != 0) { 298 udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES; 299 } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) { 300 udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE; 301 } else { 302 udhLength = 0; 303 } 304 305 if (ted.msgCount > 1) { 306 udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE; 307 } 308 309 if (udhLength != 0) { 310 udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH; 311 } 312 313 limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength; 314 } else { 315 if (ted.msgCount > 1) { 316 limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER; 317 } else { 318 limit = SmsConstants.MAX_USER_DATA_BYTES; 319 } 320 } 321 322 int pos = 0; // Index in code units. 323 int textLen = text.length(); 324 ArrayList<String> result = new ArrayList<String>(ted.msgCount); 325 while (pos < textLen) { 326 int nextPos = 0; // Counts code units. 327 if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) { 328 if (activePhone == PHONE_TYPE_CDMA && ted.msgCount == 1) { 329 // For a singleton CDMA message, the encoding must be ASCII... 330 nextPos = pos + Math.min(limit, textLen - pos); 331 } else { 332 // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode). 333 nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit, 334 ted.languageTable, ted.languageShiftTable); 335 } 336 } else { // Assume unicode. 337 nextPos = pos + Math.min(limit / 2, textLen - pos); 338 } 339 if ((nextPos <= pos) || (nextPos > textLen)) { 340 Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " + 341 nextPos + " >= " + textLen + ")"); 342 break; 343 } 344 result.add(text.substring(pos, nextPos)); 345 pos = nextPos; 346 } 347 return result; 348 } 349 350 /** 351 * Calculates the number of SMS's required to encode the message body and 352 * the number of characters remaining until the next message, given the 353 * current encoding. 354 * 355 * @param messageBody the message to encode 356 * @param use7bitOnly if true, characters that are not part of the radio 357 * specific (GSM / CDMA) alphabet encoding are converted to as a 358 * single space characters. If false, a messageBody containing 359 * non-GSM or non-CDMA alphabet characters are encoded using 360 * 16-bit encoding. 361 * @return an int[4] with int[0] being the number of SMS's required, int[1] 362 * the number of code units used, and int[2] is the number of code 363 * units remaining until the next message. int[3] is the encoding 364 * type that should be used for the message. 365 */ 366 public static int[] calculateLength(String messageBody, boolean use7bitOnly) { 367 return calculateLength((CharSequence)messageBody, use7bitOnly); 368 } 369 370 /* 371 * TODO(cleanup): It looks like there is now no useful reason why 372 * apps should generate pdus themselves using these routines, 373 * instead of handing the raw data to SMSDispatcher (and thereby 374 * have the phone process do the encoding). Moreover, CDMA now 375 * has shared state (in the form of the msgId system property) 376 * which can only be modified by the phone process, and hence 377 * makes the output of these routines incorrect. Since they now 378 * serve no purpose, they should probably just return null 379 * directly, and be deprecated. Going further in that direction, 380 * the above parsers of serialized pdu data should probably also 381 * be gotten rid of, hiding all but the necessarily visible 382 * structured data from client apps. A possible concern with 383 * doing this is that apps may be using these routines to generate 384 * pdus that are then sent elsewhere, some network server, for 385 * example, and that always returning null would thereby break 386 * otherwise useful apps. 387 */ 388 389 /** 390 * Get an SMS-SUBMIT PDU for a destination address and a message. 391 * This method will not attempt to use any GSM national language 7 bit encodings. 392 * 393 * @param scAddress Service Centre address. Null means use default. 394 * @return a <code>SubmitPdu</code> containing the encoded SC 395 * address, if applicable, and the encoded message. 396 * Returns null on encode error. 397 */ 398 public static SubmitPdu getSubmitPdu(String scAddress, 399 String destinationAddress, String message, boolean statusReportRequested) { 400 SubmitPduBase spb; 401 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 402 403 if (PHONE_TYPE_CDMA == activePhone) { 404 spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, 405 destinationAddress, message, statusReportRequested, null); 406 } else { 407 spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, 408 destinationAddress, message, statusReportRequested); 409 } 410 411 return new SubmitPdu(spb); 412 } 413 414 /** 415 * Get an SMS-SUBMIT PDU for a data message to a destination address & port. 416 * This method will not attempt to use any GSM national language 7 bit encodings. 417 * 418 * @param scAddress Service Centre address. null == use default 419 * @param destinationAddress the address of the destination for the message 420 * @param destinationPort the port to deliver the message to at the 421 * destination 422 * @param data the data for the message 423 * @return a <code>SubmitPdu</code> containing the encoded SC 424 * address, if applicable, and the encoded message. 425 * Returns null on encode error. 426 */ 427 public static SubmitPdu getSubmitPdu(String scAddress, 428 String destinationAddress, short destinationPort, byte[] data, 429 boolean statusReportRequested) { 430 SubmitPduBase spb; 431 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 432 433 if (PHONE_TYPE_CDMA == activePhone) { 434 spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, 435 destinationAddress, destinationPort, data, statusReportRequested); 436 } else { 437 spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, 438 destinationAddress, destinationPort, data, statusReportRequested); 439 } 440 441 return new SubmitPdu(spb); 442 } 443 444 /** 445 * Returns the address of the SMS service center that relayed this message 446 * or null if there is none. 447 */ 448 public String getServiceCenterAddress() { 449 return mWrappedSmsMessage.getServiceCenterAddress(); 450 } 451 452 /** 453 * Returns the originating address (sender) of this SMS message in String 454 * form or null if unavailable 455 */ 456 public String getOriginatingAddress() { 457 return mWrappedSmsMessage.getOriginatingAddress(); 458 } 459 460 /** 461 * Returns the originating address, or email from address if this message 462 * was from an email gateway. Returns null if originating address 463 * unavailable. 464 */ 465 public String getDisplayOriginatingAddress() { 466 return mWrappedSmsMessage.getDisplayOriginatingAddress(); 467 } 468 469 /** 470 * Returns the message body as a String, if it exists and is text based. 471 * @return message body is there is one, otherwise null 472 */ 473 public String getMessageBody() { 474 return mWrappedSmsMessage.getMessageBody(); 475 } 476 477 /** 478 * Returns the class of this message. 479 */ 480 public MessageClass getMessageClass() { 481 switch(mWrappedSmsMessage.getMessageClass()) { 482 case CLASS_0: return MessageClass.CLASS_0; 483 case CLASS_1: return MessageClass.CLASS_1; 484 case CLASS_2: return MessageClass.CLASS_2; 485 case CLASS_3: return MessageClass.CLASS_3; 486 default: return MessageClass.UNKNOWN; 487 488 } 489 } 490 491 /** 492 * Returns the message body, or email message body if this message was from 493 * an email gateway. Returns null if message body unavailable. 494 */ 495 public String getDisplayMessageBody() { 496 return mWrappedSmsMessage.getDisplayMessageBody(); 497 } 498 499 /** 500 * Unofficial convention of a subject line enclosed in parens empty string 501 * if not present 502 */ 503 public String getPseudoSubject() { 504 return mWrappedSmsMessage.getPseudoSubject(); 505 } 506 507 /** 508 * Returns the service centre timestamp in currentTimeMillis() format 509 */ 510 public long getTimestampMillis() { 511 return mWrappedSmsMessage.getTimestampMillis(); 512 } 513 514 /** 515 * Returns true if message is an email. 516 * 517 * @return true if this message came through an email gateway and email 518 * sender / subject / parsed body are available 519 */ 520 public boolean isEmail() { 521 return mWrappedSmsMessage.isEmail(); 522 } 523 524 /** 525 * @return if isEmail() is true, body of the email sent through the gateway. 526 * null otherwise 527 */ 528 public String getEmailBody() { 529 return mWrappedSmsMessage.getEmailBody(); 530 } 531 532 /** 533 * @return if isEmail() is true, email from address of email sent through 534 * the gateway. null otherwise 535 */ 536 public String getEmailFrom() { 537 return mWrappedSmsMessage.getEmailFrom(); 538 } 539 540 /** 541 * Get protocol identifier. 542 */ 543 public int getProtocolIdentifier() { 544 return mWrappedSmsMessage.getProtocolIdentifier(); 545 } 546 547 /** 548 * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" 549 * SMS 550 */ 551 public boolean isReplace() { 552 return mWrappedSmsMessage.isReplace(); 553 } 554 555 /** 556 * Returns true for CPHS MWI toggle message. 557 * 558 * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section 559 * B.4.2 560 */ 561 public boolean isCphsMwiMessage() { 562 return mWrappedSmsMessage.isCphsMwiMessage(); 563 } 564 565 /** 566 * returns true if this message is a CPHS voicemail / message waiting 567 * indicator (MWI) clear message 568 */ 569 public boolean isMWIClearMessage() { 570 return mWrappedSmsMessage.isMWIClearMessage(); 571 } 572 573 /** 574 * returns true if this message is a CPHS voicemail / message waiting 575 * indicator (MWI) set message 576 */ 577 public boolean isMWISetMessage() { 578 return mWrappedSmsMessage.isMWISetMessage(); 579 } 580 581 /** 582 * returns true if this message is a "Message Waiting Indication Group: 583 * Discard Message" notification and should not be stored. 584 */ 585 public boolean isMwiDontStore() { 586 return mWrappedSmsMessage.isMwiDontStore(); 587 } 588 589 /** 590 * returns the user data section minus the user data header if one was 591 * present. 592 */ 593 public byte[] getUserData() { 594 return mWrappedSmsMessage.getUserData(); 595 } 596 597 /** 598 * Returns the raw PDU for the message. 599 * 600 * @return the raw PDU for the message. 601 */ 602 public byte[] getPdu() { 603 return mWrappedSmsMessage.getPdu(); 604 } 605 606 /** 607 * Returns the status of the message on the SIM (read, unread, sent, unsent). 608 * 609 * @return the status of the message on the SIM. These are: 610 * SmsManager.STATUS_ON_SIM_FREE 611 * SmsManager.STATUS_ON_SIM_READ 612 * SmsManager.STATUS_ON_SIM_UNREAD 613 * SmsManager.STATUS_ON_SIM_SEND 614 * SmsManager.STATUS_ON_SIM_UNSENT 615 * @deprecated Use getStatusOnIcc instead. 616 */ 617 @Deprecated public int getStatusOnSim() { 618 return mWrappedSmsMessage.getStatusOnIcc(); 619 } 620 621 /** 622 * Returns the status of the message on the ICC (read, unread, sent, unsent). 623 * 624 * @return the status of the message on the ICC. These are: 625 * SmsManager.STATUS_ON_ICC_FREE 626 * SmsManager.STATUS_ON_ICC_READ 627 * SmsManager.STATUS_ON_ICC_UNREAD 628 * SmsManager.STATUS_ON_ICC_SEND 629 * SmsManager.STATUS_ON_ICC_UNSENT 630 */ 631 public int getStatusOnIcc() { 632 return mWrappedSmsMessage.getStatusOnIcc(); 633 } 634 635 /** 636 * Returns the record index of the message on the SIM (1-based index). 637 * @return the record index of the message on the SIM, or -1 if this 638 * SmsMessage was not created from a SIM SMS EF record. 639 * @deprecated Use getIndexOnIcc instead. 640 */ 641 @Deprecated public int getIndexOnSim() { 642 return mWrappedSmsMessage.getIndexOnIcc(); 643 } 644 645 /** 646 * Returns the record index of the message on the ICC (1-based index). 647 * @return the record index of the message on the ICC, or -1 if this 648 * SmsMessage was not created from a ICC SMS EF record. 649 */ 650 public int getIndexOnIcc() { 651 return mWrappedSmsMessage.getIndexOnIcc(); 652 } 653 654 /** 655 * GSM: 656 * For an SMS-STATUS-REPORT message, this returns the status field from 657 * the status report. This field indicates the status of a previously 658 * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a 659 * description of values. 660 * CDMA: 661 * For not interfering with status codes from GSM, the value is 662 * shifted to the bits 31-16. 663 * The value is composed of an error class (bits 25-24) and a status code (bits 23-16). 664 * Possible codes are described in C.S0015-B, v2.0, 4.5.21. 665 * 666 * @return 0 indicates the previously sent message was received. 667 * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21 668 * for a description of other possible values. 669 */ 670 public int getStatus() { 671 return mWrappedSmsMessage.getStatus(); 672 } 673 674 /** 675 * Return true iff the message is a SMS-STATUS-REPORT message. 676 */ 677 public boolean isStatusReportMessage() { 678 return mWrappedSmsMessage.isStatusReportMessage(); 679 } 680 681 /** 682 * Returns true iff the <code>TP-Reply-Path</code> bit is set in 683 * this message. 684 */ 685 public boolean isReplyPathPresent() { 686 return mWrappedSmsMessage.isReplyPathPresent(); 687 } 688} 689