|
32 | 32 | import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress; |
33 | 33 | import com.android.internal.telephony.cdma.sms.SmsEnvelope; |
34 | 34 | import com.android.internal.telephony.cdma.sms.UserData; |
| 35 | +import com.android.internal.util.BitwiseInputStream; |
35 | 36 | import com.android.internal.util.HexDump; |
36 | 37 |
|
37 | 38 | import java.io.BufferedInputStream; |
@@ -72,6 +73,16 @@ public class SmsMessage extends SmsMessageBase { |
72 | 73 | static final String LOG_TAG = "CDMA"; |
73 | 74 | static private final String LOGGABLE_TAG = "CDMA:SMS"; |
74 | 75 |
|
| 76 | + private final static byte TELESERVICE_IDENTIFIER = 0x00; |
| 77 | + private final static byte SERVICE_CATEGORY = 0x01; |
| 78 | + private final static byte ORIGINATING_ADDRESS = 0x02; |
| 79 | + private final static byte ORIGINATING_SUB_ADDRESS = 0x03; |
| 80 | + private final static byte DESTINATION_ADDRESS = 0x04; |
| 81 | + private final static byte DESTINATION_SUB_ADDRESS = 0x05; |
| 82 | + private final static byte BEARER_REPLY_OPTION = 0x06; |
| 83 | + private final static byte CAUSE_CODES = 0x07; |
| 84 | + private final static byte BEARER_DATA = 0x08; |
| 85 | + |
75 | 86 | /** |
76 | 87 | * Status of a previously submitted SMS. |
77 | 88 | * This field applies to SMS Delivery Acknowledge messages. 0 indicates success; |
@@ -267,6 +278,7 @@ public static SmsMessage createFromEfRecord(int index, byte[] data) { |
267 | 278 | System.arraycopy(data, 2, pdu, 0, size); |
268 | 279 | // the message has to be parsed before it can be displayed |
269 | 280 | // see gsm.SmsMessage |
| 281 | + msg.parsePduFromEfRecord(pdu); |
270 | 282 | return msg; |
271 | 283 | } catch (RuntimeException ex) { |
272 | 284 | Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); |
@@ -538,6 +550,143 @@ private void parsePdu(byte[] pdu) { |
538 | 550 | parseSms(); |
539 | 551 | } |
540 | 552 |
|
| 553 | + /** |
| 554 | + * Decodes 3GPP2 sms stored in CSIM/RUIM cards As per 3GPP2 C.S0015-0 |
| 555 | + */ |
| 556 | + private void parsePduFromEfRecord(byte[] pdu) { |
| 557 | + ByteArrayInputStream bais = new ByteArrayInputStream(pdu); |
| 558 | + DataInputStream dis = new DataInputStream(bais); |
| 559 | + SmsEnvelope env = new SmsEnvelope(); |
| 560 | + CdmaSmsAddress addr = new CdmaSmsAddress(); |
| 561 | + CdmaSmsSubaddress subAddr = new CdmaSmsSubaddress(); |
| 562 | + |
| 563 | + try { |
| 564 | + env.messageType = dis.readByte(); |
| 565 | + |
| 566 | + while (dis.available() > 0) { |
| 567 | + int parameterId = dis.readByte(); |
| 568 | + int parameterLen = dis.readByte(); |
| 569 | + byte[] parameterData = new byte[parameterLen]; |
| 570 | + |
| 571 | + switch (parameterId) { |
| 572 | + case TELESERVICE_IDENTIFIER: |
| 573 | + /* |
| 574 | + * 16 bit parameter that identifies which upper layer |
| 575 | + * service access point is sending or should receive |
| 576 | + * this message |
| 577 | + */ |
| 578 | + env.teleService = dis.readUnsignedShort(); |
| 579 | + Log.i(LOG_TAG, "teleservice = " + env.teleService); |
| 580 | + break; |
| 581 | + case SERVICE_CATEGORY: |
| 582 | + /* |
| 583 | + * 16 bit parameter that identifies type of service as |
| 584 | + * in 3GPP2 C.S0015-0 Table 3.4.3.2-1 |
| 585 | + */ |
| 586 | + env.serviceCategory = dis.readUnsignedShort(); |
| 587 | + break; |
| 588 | + case ORIGINATING_ADDRESS: |
| 589 | + case DESTINATION_ADDRESS: |
| 590 | + dis.read(parameterData, 0, parameterLen); |
| 591 | + BitwiseInputStream addrBis = new BitwiseInputStream(parameterData); |
| 592 | + addr.digitMode = addrBis.read(1); |
| 593 | + addr.numberMode = addrBis.read(1); |
| 594 | + int numberType = 0; |
| 595 | + if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) { |
| 596 | + numberType = addrBis.read(3); |
| 597 | + addr.ton = numberType; |
| 598 | + |
| 599 | + if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK) |
| 600 | + addr.numberPlan = addrBis.read(4); |
| 601 | + } |
| 602 | + |
| 603 | + addr.numberOfDigits = addrBis.read(8); |
| 604 | + |
| 605 | + byte[] data = new byte[addr.numberOfDigits]; |
| 606 | + byte b = 0x00; |
| 607 | + |
| 608 | + if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) { |
| 609 | + /* As per 3GPP2 C.S0005-0 Table 2.7.1.3.2.4-4 */ |
| 610 | + for (int index = 0; index < addr.numberOfDigits; index++) { |
| 611 | + b = (byte) (0xF & addrBis.read(4)); |
| 612 | + // convert the value if it is 4-bit DTMF to 8 |
| 613 | + // bit |
| 614 | + data[index] = convertDtmfToAscii(b); |
| 615 | + } |
| 616 | + } else if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) { |
| 617 | + if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK) { |
| 618 | + for (int index = 0; index < addr.numberOfDigits; index++) { |
| 619 | + b = (byte) (0xFF & addrBis.read(8)); |
| 620 | + data[index] = b; |
| 621 | + } |
| 622 | + |
| 623 | + } else if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK) { |
| 624 | + if (numberType == 2) |
| 625 | + Log.e(LOG_TAG, "TODO: Originating Addr is email id"); |
| 626 | + else |
| 627 | + Log.e(LOG_TAG, |
| 628 | + "TODO: Originating Addr is data network address"); |
| 629 | + } else { |
| 630 | + Log.e(LOG_TAG, "Originating Addr is of incorrect type"); |
| 631 | + } |
| 632 | + } else { |
| 633 | + Log.e(LOG_TAG, "Incorrect Digit mode"); |
| 634 | + } |
| 635 | + addr.origBytes = data; |
| 636 | + Log.i(LOG_TAG, "Originating Addr=" + addr.toString()); |
| 637 | + break; |
| 638 | + case ORIGINATING_SUB_ADDRESS: |
| 639 | + case DESTINATION_SUB_ADDRESS: |
| 640 | + dis.read(parameterData, 0, parameterLen); |
| 641 | + BitwiseInputStream subAddrBis = new BitwiseInputStream(parameterData); |
| 642 | + subAddr.type = subAddrBis.read(3); |
| 643 | + subAddr.odd = subAddrBis.readByteArray(1)[0]; |
| 644 | + int subAddrLen = subAddrBis.read(8); |
| 645 | + byte[] subdata = new byte[subAddrLen]; |
| 646 | + for (int index = 0; index < subAddrLen; index++) { |
| 647 | + b = (byte) (0xFF & subAddrBis.read(4)); |
| 648 | + // convert the value if it is 4-bit DTMF to 8 bit |
| 649 | + subdata[index] = convertDtmfToAscii(b); |
| 650 | + } |
| 651 | + subAddr.origBytes = subdata; |
| 652 | + break; |
| 653 | + case BEARER_REPLY_OPTION: |
| 654 | + dis.read(parameterData, 0, parameterLen); |
| 655 | + BitwiseInputStream replyOptBis = new BitwiseInputStream(parameterData); |
| 656 | + env.bearerReply = replyOptBis.read(6); |
| 657 | + break; |
| 658 | + case CAUSE_CODES: |
| 659 | + dis.read(parameterData, 0, parameterLen); |
| 660 | + BitwiseInputStream ccBis = new BitwiseInputStream(parameterData); |
| 661 | + env.replySeqNo = ccBis.readByteArray(6)[0]; |
| 662 | + env.errorClass = ccBis.readByteArray(2)[0]; |
| 663 | + if (env.errorClass != 0x00) |
| 664 | + env.causeCode = ccBis.readByteArray(8)[0]; |
| 665 | + break; |
| 666 | + case BEARER_DATA: |
| 667 | + dis.read(parameterData, 0, parameterLen); |
| 668 | + env.bearerData = parameterData; |
| 669 | + break; |
| 670 | + default: |
| 671 | + throw new Exception("unsupported parameterId (" + parameterId + ")"); |
| 672 | + } |
| 673 | + } |
| 674 | + bais.close(); |
| 675 | + dis.close(); |
| 676 | + } catch (Exception ex) { |
| 677 | + Log.e(LOG_TAG, "parsePduFromEfRecord: conversion from pdu to SmsMessage failed" + ex); |
| 678 | + } |
| 679 | + |
| 680 | + // link the filled objects to this SMS |
| 681 | + originatingAddress = addr; |
| 682 | + env.origAddress = addr; |
| 683 | + env.origSubaddress = subAddr; |
| 684 | + mEnvelope = env; |
| 685 | + mPdu = pdu; |
| 686 | + |
| 687 | + parseSms(); |
| 688 | + } |
| 689 | + |
541 | 690 | /** |
542 | 691 | * Parses a SMS message from its BearerData stream. (mobile-terminated only) |
543 | 692 | */ |
|
0 commit comments