1767a662ecde33c3979bf02b793d392aca0403162Wink Saville/* 2767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Copyright (C) 2006 The Android Open Source Project 3767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 4767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Licensed under the Apache License, Version 2.0 (the "License"); 5767a662ecde33c3979bf02b793d392aca0403162Wink Saville * you may not use this file except in compliance with the License. 6767a662ecde33c3979bf02b793d392aca0403162Wink Saville * You may obtain a copy of the License at 7767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 8767a662ecde33c3979bf02b793d392aca0403162Wink Saville * http://www.apache.org/licenses/LICENSE-2.0 9767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 10767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Unless required by applicable law or agreed to in writing, software 11767a662ecde33c3979bf02b793d392aca0403162Wink Saville * distributed under the License is distributed on an "AS IS" BASIS, 12767a662ecde33c3979bf02b793d392aca0403162Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13767a662ecde33c3979bf02b793d392aca0403162Wink Saville * See the License for the specific language governing permissions and 14767a662ecde33c3979bf02b793d392aca0403162Wink Saville * limitations under the License. 15767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 16767a662ecde33c3979bf02b793d392aca0403162Wink Saville 17767a662ecde33c3979bf02b793d392aca0403162Wink Savillepackage com.android.internal.telephony.gsm; 18767a662ecde33c3979bf02b793d392aca0403162Wink Saville 19767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.telephony.PhoneNumberUtils; 20767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.text.format.Time; 21767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.util.Log; 2287d14a1756f2ff4abdc107de35d06739245a606eJake Hamby 23767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.EncodeException; 24767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.GsmAlphabet; 2587d14a1756f2ff4abdc107de35d06739245a606eJake Hambyimport com.android.internal.telephony.IccUtils; 26767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SmsHeader; 27767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SmsMessageBase; 28767a662ecde33c3979bf02b793d392aca0403162Wink Saville 29767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport java.io.ByteArrayOutputStream; 30767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport java.io.UnsupportedEncodingException; 31767a662ecde33c3979bf02b793d392aca0403162Wink Saville 3287d14a1756f2ff4abdc107de35d06739245a606eJake Hambyimport static android.telephony.SmsMessage.ENCODING_16BIT; 33767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.ENCODING_7BIT; 34767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.ENCODING_8BIT; 35b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Leeimport static android.telephony.SmsMessage.ENCODING_KSC5601; 36767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.ENCODING_UNKNOWN; 37767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; 38767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; 39767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; 40767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MessageClass; 41767a662ecde33c3979bf02b793d392aca0403162Wink Saville 42767a662ecde33c3979bf02b793d392aca0403162Wink Saville/** 43767a662ecde33c3979bf02b793d392aca0403162Wink Saville * A Short Message Service message. 44767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 45767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 46145ff609de3206b585819ef974fab20cdc2d9f5eJake Hambypublic class SmsMessage extends SmsMessageBase { 47767a662ecde33c3979bf02b793d392aca0403162Wink Saville static final String LOG_TAG = "GSM"; 48767a662ecde33c3979bf02b793d392aca0403162Wink Saville 49767a662ecde33c3979bf02b793d392aca0403162Wink Saville private MessageClass messageClass; 50767a662ecde33c3979bf02b793d392aca0403162Wink Saville 51767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 52767a662ecde33c3979bf02b793d392aca0403162Wink Saville * TP-Message-Type-Indicator 53767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 9.2.3 54767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 55767a662ecde33c3979bf02b793d392aca0403162Wink Saville private int mti; 56767a662ecde33c3979bf02b793d392aca0403162Wink Saville 57767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** TP-Protocol-Identifier (TP-PID) */ 58767a662ecde33c3979bf02b793d392aca0403162Wink Saville private int protocolIdentifier; 59767a662ecde33c3979bf02b793d392aca0403162Wink Saville 60767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Data-Coding-Scheme 61767a662ecde33c3979bf02b793d392aca0403162Wink Saville // see TS 23.038 62767a662ecde33c3979bf02b793d392aca0403162Wink Saville private int dataCodingScheme; 63767a662ecde33c3979bf02b793d392aca0403162Wink Saville 64767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Reply-Path 65767a662ecde33c3979bf02b793d392aca0403162Wink Saville // e.g. 23.040 9.2.2.1 66767a662ecde33c3979bf02b793d392aca0403162Wink Saville private boolean replyPathPresent = false; 67767a662ecde33c3979bf02b793d392aca0403162Wink Saville 68767a662ecde33c3979bf02b793d392aca0403162Wink Saville // "Message Marked for Automatic Deletion Group" 69767a662ecde33c3979bf02b793d392aca0403162Wink Saville // 23.038 Section 4 70767a662ecde33c3979bf02b793d392aca0403162Wink Saville private boolean automaticDeletion; 71767a662ecde33c3979bf02b793d392aca0403162Wink Saville 72767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** True if Status Report is for SMS-SUBMIT; false for SMS-COMMAND. */ 73767a662ecde33c3979bf02b793d392aca0403162Wink Saville private boolean forSubmit; 74767a662ecde33c3979bf02b793d392aca0403162Wink Saville 75767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** The address of the receiver. */ 76767a662ecde33c3979bf02b793d392aca0403162Wink Saville private GsmSmsAddress recipientAddress; 77767a662ecde33c3979bf02b793d392aca0403162Wink Saville 78767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** Time when SMS-SUBMIT was delivered from SC to MSE. */ 79767a662ecde33c3979bf02b793d392aca0403162Wink Saville private long dischargeTimeMillis; 80767a662ecde33c3979bf02b793d392aca0403162Wink Saville 81767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 82767a662ecde33c3979bf02b793d392aca0403162Wink Saville * TP-Status - status of a previously submitted SMS. 83767a662ecde33c3979bf02b793d392aca0403162Wink Saville * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; 84767a662ecde33c3979bf02b793d392aca0403162Wink Saville * see TS 23.040, 9.2.3.15 for description of other possible values. 85767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 86767a662ecde33c3979bf02b793d392aca0403162Wink Saville private int status; 87767a662ecde33c3979bf02b793d392aca0403162Wink Saville 88767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 89767a662ecde33c3979bf02b793d392aca0403162Wink Saville * TP-Status - status of a previously submitted SMS. 90767a662ecde33c3979bf02b793d392aca0403162Wink Saville * This field is true iff the message is a SMS-STATUS-REPORT message. 91767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 92767a662ecde33c3979bf02b793d392aca0403162Wink Saville private boolean isStatusReportMessage = false; 93767a662ecde33c3979bf02b793d392aca0403162Wink Saville 94767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static class SubmitPdu extends SubmitPduBase { 95767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 96767a662ecde33c3979bf02b793d392aca0403162Wink Saville 97767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 98767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Create an SmsMessage from a raw PDU. 99767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 100767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static SmsMessage createFromPdu(byte[] pdu) { 101767a662ecde33c3979bf02b793d392aca0403162Wink Saville try { 102767a662ecde33c3979bf02b793d392aca0403162Wink Saville SmsMessage msg = new SmsMessage(); 103767a662ecde33c3979bf02b793d392aca0403162Wink Saville msg.parsePdu(pdu); 104767a662ecde33c3979bf02b793d392aca0403162Wink Saville return msg; 105767a662ecde33c3979bf02b793d392aca0403162Wink Saville } catch (RuntimeException ex) { 106767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 107767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 108767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 109767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 110767a662ecde33c3979bf02b793d392aca0403162Wink Saville 111767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 112c16889dc0034daaf50b2307c4de6c16c4964f30cNaveen Kalla * 3GPP TS 23.040 9.2.3.9 specifies that Type Zero messages are indicated 113c16889dc0034daaf50b2307c4de6c16c4964f30cNaveen Kalla * by TP_PID field set to value 0x40 114c16889dc0034daaf50b2307c4de6c16c4964f30cNaveen Kalla */ 115c16889dc0034daaf50b2307c4de6c16c4964f30cNaveen Kalla public boolean isTypeZero() { 116c16889dc0034daaf50b2307c4de6c16c4964f30cNaveen Kalla return (protocolIdentifier == 0x40); 117c16889dc0034daaf50b2307c4de6c16c4964f30cNaveen Kalla } 118c16889dc0034daaf50b2307c4de6c16c4964f30cNaveen Kalla 119c16889dc0034daaf50b2307c4de6c16c4964f30cNaveen Kalla /** 120767a662ecde33c3979bf02b793d392aca0403162Wink Saville * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the 121767a662ecde33c3979bf02b793d392aca0403162Wink Saville * +CMT unsolicited response (PDU mode, of course) 122767a662ecde33c3979bf02b793d392aca0403162Wink Saville * +CMT: [<alpha>],<length><CR><LF><pdu> 123767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 124767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Only public for debugging 125767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 126767a662ecde33c3979bf02b793d392aca0403162Wink Saville * {@hide} 127767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 128767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static SmsMessage newFromCMT(String[] lines) { 129767a662ecde33c3979bf02b793d392aca0403162Wink Saville try { 130767a662ecde33c3979bf02b793d392aca0403162Wink Saville SmsMessage msg = new SmsMessage(); 131767a662ecde33c3979bf02b793d392aca0403162Wink Saville msg.parsePdu(IccUtils.hexStringToBytes(lines[1])); 132767a662ecde33c3979bf02b793d392aca0403162Wink Saville return msg; 133767a662ecde33c3979bf02b793d392aca0403162Wink Saville } catch (RuntimeException ex) { 134767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 135767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 136767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 137767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 138767a662ecde33c3979bf02b793d392aca0403162Wink Saville 139767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** @hide */ 140767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static SmsMessage newFromCDS(String line) { 141767a662ecde33c3979bf02b793d392aca0403162Wink Saville try { 142767a662ecde33c3979bf02b793d392aca0403162Wink Saville SmsMessage msg = new SmsMessage(); 143767a662ecde33c3979bf02b793d392aca0403162Wink Saville msg.parsePdu(IccUtils.hexStringToBytes(line)); 144767a662ecde33c3979bf02b793d392aca0403162Wink Saville return msg; 145767a662ecde33c3979bf02b793d392aca0403162Wink Saville } catch (RuntimeException ex) { 146767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); 147767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 148767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 149767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 150767a662ecde33c3979bf02b793d392aca0403162Wink Saville 151767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 152767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Create an SmsMessage from an SMS EF record. 153767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 154767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param index Index of SMS record. This should be index in ArrayList 155767a662ecde33c3979bf02b793d392aca0403162Wink Saville * returned by SmsManager.getAllMessagesFromSim + 1. 156767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param data Record data. 157767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @return An SmsMessage representing the record. 158767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 159767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @hide 160767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 161767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static SmsMessage createFromEfRecord(int index, byte[] data) { 162767a662ecde33c3979bf02b793d392aca0403162Wink Saville try { 163767a662ecde33c3979bf02b793d392aca0403162Wink Saville SmsMessage msg = new SmsMessage(); 164767a662ecde33c3979bf02b793d392aca0403162Wink Saville 165767a662ecde33c3979bf02b793d392aca0403162Wink Saville msg.indexOnIcc = index; 166767a662ecde33c3979bf02b793d392aca0403162Wink Saville 167767a662ecde33c3979bf02b793d392aca0403162Wink Saville // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, 168767a662ecde33c3979bf02b793d392aca0403162Wink Saville // or STORED_UNSENT 169767a662ecde33c3979bf02b793d392aca0403162Wink Saville // See TS 51.011 10.5.3 170767a662ecde33c3979bf02b793d392aca0403162Wink Saville if ((data[0] & 1) == 0) { 171767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.w(LOG_TAG, 172767a662ecde33c3979bf02b793d392aca0403162Wink Saville "SMS parsing failed: Trying to parse a free record"); 173767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 174767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 175767a662ecde33c3979bf02b793d392aca0403162Wink Saville msg.statusOnIcc = data[0] & 0x07; 176767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 177767a662ecde33c3979bf02b793d392aca0403162Wink Saville 178767a662ecde33c3979bf02b793d392aca0403162Wink Saville int size = data.length - 1; 179767a662ecde33c3979bf02b793d392aca0403162Wink Saville 180767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Note: Data may include trailing FF's. That's OK; message 181767a662ecde33c3979bf02b793d392aca0403162Wink Saville // should still parse correctly. 182767a662ecde33c3979bf02b793d392aca0403162Wink Saville byte[] pdu = new byte[size]; 183767a662ecde33c3979bf02b793d392aca0403162Wink Saville System.arraycopy(data, 1, pdu, 0, size); 184767a662ecde33c3979bf02b793d392aca0403162Wink Saville msg.parsePdu(pdu); 185767a662ecde33c3979bf02b793d392aca0403162Wink Saville return msg; 186767a662ecde33c3979bf02b793d392aca0403162Wink Saville } catch (RuntimeException ex) { 187767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 188767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 189767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 190767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 191767a662ecde33c3979bf02b793d392aca0403162Wink Saville 192767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 193767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the 194767a662ecde33c3979bf02b793d392aca0403162Wink Saville * length in bytes (not hex chars) less the SMSC header 195767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 196767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static int getTPLayerLengthForPDU(String pdu) { 197767a662ecde33c3979bf02b793d392aca0403162Wink Saville int len = pdu.length() / 2; 198b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby int smscLen = Integer.parseInt(pdu.substring(0, 2), 16); 199767a662ecde33c3979bf02b793d392aca0403162Wink Saville 200767a662ecde33c3979bf02b793d392aca0403162Wink Saville return len - smscLen - 1; 201767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 202767a662ecde33c3979bf02b793d392aca0403162Wink Saville 203767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 204767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Get an SMS-SUBMIT PDU for a destination address and a message 205767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 206767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param scAddress Service Centre address. Null means use default. 207767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 208767a662ecde33c3979bf02b793d392aca0403162Wink Saville * address, if applicable, and the encoded message. 209767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Returns null on encode error. 210767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @hide 211767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 212767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static SubmitPdu getSubmitPdu(String scAddress, 213767a662ecde33c3979bf02b793d392aca0403162Wink Saville String destinationAddress, String message, 214767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean statusReportRequested, byte[] header) { 2151fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header, 216b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby ENCODING_UNKNOWN, 0, 0); 2171fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } 2181fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq 2191fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq 2201fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq /** 2211fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * Get an SMS-SUBMIT PDU for a destination address and a message using the 2221fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * specified encoding. 2231fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * 2241fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * @param scAddress Service Centre address. Null means use default. 2251fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * @param encoding Encoding defined by constants in android.telephony.SmsMessage.ENCODING_* 226b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby * @param languageTable 227b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby * @param languageShiftTable 2281fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * @return a <code>SubmitPdu</code> containing the encoded SC 2291fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * address, if applicable, and the encoded message. 2301fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * Returns null on encode error. 2311fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * @hide 2321fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq */ 2331fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq public static SubmitPdu getSubmitPdu(String scAddress, 2341fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq String destinationAddress, String message, 235b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby boolean statusReportRequested, byte[] header, int encoding, 236b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby int languageTable, int languageShiftTable) { 237767a662ecde33c3979bf02b793d392aca0403162Wink Saville 238767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Perform null parameter checks. 239767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (message == null || destinationAddress == null) { 240767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 241767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 242767a662ecde33c3979bf02b793d392aca0403162Wink Saville 24387d14a1756f2ff4abdc107de35d06739245a606eJake Hamby if (encoding == ENCODING_UNKNOWN) { 24487d14a1756f2ff4abdc107de35d06739245a606eJake Hamby // Find the best encoding to use 24587d14a1756f2ff4abdc107de35d06739245a606eJake Hamby TextEncodingDetails ted = calculateLength(message, false); 24687d14a1756f2ff4abdc107de35d06739245a606eJake Hamby encoding = ted.codeUnitSize; 24787d14a1756f2ff4abdc107de35d06739245a606eJake Hamby languageTable = ted.languageTable; 24887d14a1756f2ff4abdc107de35d06739245a606eJake Hamby languageShiftTable = ted.languageShiftTable; 24987d14a1756f2ff4abdc107de35d06739245a606eJake Hamby 25087d14a1756f2ff4abdc107de35d06739245a606eJake Hamby if (encoding == ENCODING_7BIT && (languageTable != 0 || languageShiftTable != 0)) { 25187d14a1756f2ff4abdc107de35d06739245a606eJake Hamby if (header != null) { 25287d14a1756f2ff4abdc107de35d06739245a606eJake Hamby SmsHeader smsHeader = SmsHeader.fromByteArray(header); 25387d14a1756f2ff4abdc107de35d06739245a606eJake Hamby if (smsHeader.languageTable != languageTable 25487d14a1756f2ff4abdc107de35d06739245a606eJake Hamby || smsHeader.languageShiftTable != languageShiftTable) { 25587d14a1756f2ff4abdc107de35d06739245a606eJake Hamby Log.w(LOG_TAG, "Updating language table in SMS header: " 25687d14a1756f2ff4abdc107de35d06739245a606eJake Hamby + smsHeader.languageTable + " -> " + languageTable + ", " 25787d14a1756f2ff4abdc107de35d06739245a606eJake Hamby + smsHeader.languageShiftTable + " -> " + languageShiftTable); 25887d14a1756f2ff4abdc107de35d06739245a606eJake Hamby smsHeader.languageTable = languageTable; 25987d14a1756f2ff4abdc107de35d06739245a606eJake Hamby smsHeader.languageShiftTable = languageShiftTable; 26087d14a1756f2ff4abdc107de35d06739245a606eJake Hamby header = SmsHeader.toByteArray(smsHeader); 26187d14a1756f2ff4abdc107de35d06739245a606eJake Hamby } 26287d14a1756f2ff4abdc107de35d06739245a606eJake Hamby } else { 26387d14a1756f2ff4abdc107de35d06739245a606eJake Hamby SmsHeader smsHeader = new SmsHeader(); 26487d14a1756f2ff4abdc107de35d06739245a606eJake Hamby smsHeader.languageTable = languageTable; 26587d14a1756f2ff4abdc107de35d06739245a606eJake Hamby smsHeader.languageShiftTable = languageShiftTable; 26687d14a1756f2ff4abdc107de35d06739245a606eJake Hamby header = SmsHeader.toByteArray(smsHeader); 26787d14a1756f2ff4abdc107de35d06739245a606eJake Hamby } 26887d14a1756f2ff4abdc107de35d06739245a606eJake Hamby } 26987d14a1756f2ff4abdc107de35d06739245a606eJake Hamby } 27087d14a1756f2ff4abdc107de35d06739245a606eJake Hamby 271767a662ecde33c3979bf02b793d392aca0403162Wink Saville SubmitPdu ret = new SubmitPdu(); 272767a662ecde33c3979bf02b793d392aca0403162Wink Saville // MTI = SMS-SUBMIT, UDHI = header != null 273767a662ecde33c3979bf02b793d392aca0403162Wink Saville byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); 274767a662ecde33c3979bf02b793d392aca0403162Wink Saville ByteArrayOutputStream bo = getSubmitPduHead( 275767a662ecde33c3979bf02b793d392aca0403162Wink Saville scAddress, destinationAddress, mtiByte, 276767a662ecde33c3979bf02b793d392aca0403162Wink Saville statusReportRequested, ret); 27787d14a1756f2ff4abdc107de35d06739245a606eJake Hamby 2781fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq // User Data (and length) 2791fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq byte[] userData; 2801fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq try { 2811fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq if (encoding == ENCODING_7BIT) { 282b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header, 283b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby languageTable, languageShiftTable); 2841fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } else { //assume UCS-2 2851fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq try { 2861fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq userData = encodeUCS2(message, header); 2871fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } catch(UnsupportedEncodingException uex) { 2881fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq Log.e(LOG_TAG, 2891fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq "Implausible UnsupportedEncodingException ", 2901fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq uex); 2911fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq return null; 2921fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } 2931fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } 2941fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } catch (EncodeException ex) { 2951fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq // Encoding to the 7-bit alphabet failed. Let's see if we can 2961fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq // send it as a UCS-2 encoded message 2971fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq try { 2981fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq userData = encodeUCS2(message, header); 2990e200c3cbed83283c79703b552fe8e3d49040f10Bai Tao encoding = ENCODING_16BIT; 3001fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } catch(UnsupportedEncodingException uex) { 3011fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq Log.e(LOG_TAG, 3021fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq "Implausible UnsupportedEncodingException ", 3031fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq uex); 3041fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq return null; 3051fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } 3061fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } 307767a662ecde33c3979bf02b793d392aca0403162Wink Saville 3081fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq if (encoding == ENCODING_7BIT) { 309767a662ecde33c3979bf02b793d392aca0403162Wink Saville if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { 310767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Message too long 31187d14a1756f2ff4abdc107de35d06739245a606eJake Hamby Log.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)"); 312767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 313767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 314767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Data-Coding-Scheme 315767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Default encoding, uncompressed 316faf4413dffdc9079683b951736088ff2a01073a4jsh // To test writing messages to the SIM card, change this value 0x00 317faf4413dffdc9079683b951736088ff2a01073a4jsh // to 0x12, which means "bits 1 and 0 contain message class, and the 318faf4413dffdc9079683b951736088ff2a01073a4jsh // class is 2". Note that this takes effect for the sender. In other 319faf4413dffdc9079683b951736088ff2a01073a4jsh // words, messages sent by the phone with this change will end up on 320faf4413dffdc9079683b951736088ff2a01073a4jsh // the receiver's SIM card. You can then send messages to yourself 321faf4413dffdc9079683b951736088ff2a01073a4jsh // (on a phone with this change) and they'll end up on the SIM card. 322767a662ecde33c3979bf02b793d392aca0403162Wink Saville bo.write(0x00); 323145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby } else { // assume UCS-2 3241fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) { 325767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Message too long 32687d14a1756f2ff4abdc107de35d06739245a606eJake Hamby Log.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)"); 327767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 328767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 329767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Data-Coding-Scheme 330df0c2a94b51ead16a8b7c7b3159295bc978d9831sj // UCS-2 encoding, uncompressed 331df0c2a94b51ead16a8b7c7b3159295bc978d9831sj bo.write(0x08); 332767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 333767a662ecde33c3979bf02b793d392aca0403162Wink Saville 3341fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq // (no TP-Validity-Period) 3351fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq bo.write(userData, 0, userData.length); 336767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret.encodedMessage = bo.toByteArray(); 337767a662ecde33c3979bf02b793d392aca0403162Wink Saville return ret; 338767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 339767a662ecde33c3979bf02b793d392aca0403162Wink Saville 340767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 3411fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if necessary 3421fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * 3431fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * @return 3441fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq * @throws UnsupportedEncodingException 3451fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq */ 3461fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq private static byte[] encodeUCS2(String message, byte[] header) 3471fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq throws UnsupportedEncodingException { 3481fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq byte[] userData, textPart; 3491fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq textPart = message.getBytes("utf-16be"); 3501fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq 3511fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq if (header != null) { 3521fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq // Need 1 byte for UDHL 3531fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq userData = new byte[header.length + textPart.length + 1]; 3541fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq 3551fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq userData[0] = (byte)header.length; 3561fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq System.arraycopy(header, 0, userData, 1, header.length); 3571fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length); 3581fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } 3591fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq else { 3601fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq userData = textPart; 3611fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } 3621fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq byte[] ret = new byte[userData.length+1]; 3631fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq ret[0] = (byte) (userData.length & 0xff ); 3641fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq System.arraycopy(userData, 0, ret, 1, userData.length); 3651fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq return ret; 3661fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq } 3671fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq 3681fa7fae1399f735ea15242484fb5def187e07fdeGilles Duboscq /** 369767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Get an SMS-SUBMIT PDU for a destination address and a message 370767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 371767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param scAddress Service Centre address. Null means use default. 372767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 373767a662ecde33c3979bf02b793d392aca0403162Wink Saville * address, if applicable, and the encoded message. 374767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Returns null on encode error. 375767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 376767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static SubmitPdu getSubmitPdu(String scAddress, 377767a662ecde33c3979bf02b793d392aca0403162Wink Saville String destinationAddress, String message, 378767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean statusReportRequested) { 379767a662ecde33c3979bf02b793d392aca0403162Wink Saville 380767a662ecde33c3979bf02b793d392aca0403162Wink Saville return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); 381767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 382767a662ecde33c3979bf02b793d392aca0403162Wink Saville 383767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 384767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Get an SMS-SUBMIT PDU for a data message to a destination address & port 385767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 386767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param scAddress Service Centre address. null == use default 387767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param destinationAddress the address of the destination for the message 388767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param destinationPort the port to deliver the message to at the 389767a662ecde33c3979bf02b793d392aca0403162Wink Saville * destination 390145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby * @param data the data for the message 391767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 392767a662ecde33c3979bf02b793d392aca0403162Wink Saville * address, if applicable, and the encoded message. 393767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Returns null on encode error. 394767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 395767a662ecde33c3979bf02b793d392aca0403162Wink Saville public static SubmitPdu getSubmitPdu(String scAddress, 3961f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink String destinationAddress, int destinationPort, byte[] data, 397767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean statusReportRequested) { 39864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink 39964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs(); 40064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink portAddrs.destPort = destinationPort; 40164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink portAddrs.origPort = 0; 40264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink portAddrs.areEightBits = false; 40364c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink 40464c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink SmsHeader smsHeader = new SmsHeader(); 40564c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink smsHeader.portAddrs = portAddrs; 40664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink 40764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink byte[] smsHeaderData = SmsHeader.toByteArray(smsHeader); 40864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink 40964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink if ((data.length + smsHeaderData.length + 1) > MAX_USER_DATA_BYTES) { 410767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.e(LOG_TAG, "SMS data message may only contain " 41164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink + (MAX_USER_DATA_BYTES - smsHeaderData.length - 1) + " bytes"); 412767a662ecde33c3979bf02b793d392aca0403162Wink Saville return null; 413767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 414767a662ecde33c3979bf02b793d392aca0403162Wink Saville 415767a662ecde33c3979bf02b793d392aca0403162Wink Saville SubmitPdu ret = new SubmitPdu(); 416767a662ecde33c3979bf02b793d392aca0403162Wink Saville ByteArrayOutputStream bo = getSubmitPduHead( 417767a662ecde33c3979bf02b793d392aca0403162Wink Saville scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, 418767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-UDHI = true 419767a662ecde33c3979bf02b793d392aca0403162Wink Saville statusReportRequested, ret); 420767a662ecde33c3979bf02b793d392aca0403162Wink Saville 421767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Data-Coding-Scheme 422767a662ecde33c3979bf02b793d392aca0403162Wink Saville // No class, 8 bit data 423767a662ecde33c3979bf02b793d392aca0403162Wink Saville bo.write(0x04); 424767a662ecde33c3979bf02b793d392aca0403162Wink Saville 425767a662ecde33c3979bf02b793d392aca0403162Wink Saville // (no TP-Validity-Period) 426767a662ecde33c3979bf02b793d392aca0403162Wink Saville 42764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink // Total size 42864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink bo.write(data.length + smsHeaderData.length + 1); 429767a662ecde33c3979bf02b793d392aca0403162Wink Saville 43064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink // User data header 43164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink bo.write(smsHeaderData.length); 43264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink bo.write(smsHeaderData, 0, smsHeaderData.length); 433767a662ecde33c3979bf02b793d392aca0403162Wink Saville 434767a662ecde33c3979bf02b793d392aca0403162Wink Saville // User data 435767a662ecde33c3979bf02b793d392aca0403162Wink Saville bo.write(data, 0, data.length); 436767a662ecde33c3979bf02b793d392aca0403162Wink Saville 437767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret.encodedMessage = bo.toByteArray(); 438767a662ecde33c3979bf02b793d392aca0403162Wink Saville return ret; 439767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 440767a662ecde33c3979bf02b793d392aca0403162Wink Saville 441767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 442767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Create the beginning of a SUBMIT PDU. This is the part of the 443767a662ecde33c3979bf02b793d392aca0403162Wink Saville * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, 444767a662ecde33c3979bf02b793d392aca0403162Wink Saville * one of which takes a byte array and the other of which takes a 445767a662ecde33c3979bf02b793d392aca0403162Wink Saville * <code>String</code>. 446767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 447767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param scAddress Service Centre address. null == use default 448767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param destinationAddress the address of the destination for the message 449767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param mtiByte 450767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param ret <code>SubmitPdu</code> containing the encoded SC 451767a662ecde33c3979bf02b793d392aca0403162Wink Saville * address, if applicable, and the encoded message 452767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 453767a662ecde33c3979bf02b793d392aca0403162Wink Saville private static ByteArrayOutputStream getSubmitPduHead( 454767a662ecde33c3979bf02b793d392aca0403162Wink Saville String scAddress, String destinationAddress, byte mtiByte, 455767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean statusReportRequested, SubmitPdu ret) { 456767a662ecde33c3979bf02b793d392aca0403162Wink Saville ByteArrayOutputStream bo = new ByteArrayOutputStream( 457767a662ecde33c3979bf02b793d392aca0403162Wink Saville MAX_USER_DATA_BYTES + 40); 458767a662ecde33c3979bf02b793d392aca0403162Wink Saville 459767a662ecde33c3979bf02b793d392aca0403162Wink Saville // SMSC address with length octet, or 0 460767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (scAddress == null) { 461767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret.encodedScAddress = null; 462767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 463767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( 464767a662ecde33c3979bf02b793d392aca0403162Wink Saville scAddress); 465767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 466767a662ecde33c3979bf02b793d392aca0403162Wink Saville 467767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Message-Type-Indicator (and friends) 468767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (statusReportRequested) { 469767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Set TP-Status-Report-Request bit. 470767a662ecde33c3979bf02b793d392aca0403162Wink Saville mtiByte |= 0x20; 47143a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) Log.d(LOG_TAG, "SMS status report requested"); 472767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 473767a662ecde33c3979bf02b793d392aca0403162Wink Saville bo.write(mtiByte); 474767a662ecde33c3979bf02b793d392aca0403162Wink Saville 475767a662ecde33c3979bf02b793d392aca0403162Wink Saville // space for TP-Message-Reference 476767a662ecde33c3979bf02b793d392aca0403162Wink Saville bo.write(0); 477767a662ecde33c3979bf02b793d392aca0403162Wink Saville 478767a662ecde33c3979bf02b793d392aca0403162Wink Saville byte[] daBytes; 479767a662ecde33c3979bf02b793d392aca0403162Wink Saville 480767a662ecde33c3979bf02b793d392aca0403162Wink Saville daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); 481767a662ecde33c3979bf02b793d392aca0403162Wink Saville 482767a662ecde33c3979bf02b793d392aca0403162Wink Saville // destination address length in BCD digits, ignoring TON byte and pad 483767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TODO Should be better. 484767a662ecde33c3979bf02b793d392aca0403162Wink Saville bo.write((daBytes.length - 1) * 2 485767a662ecde33c3979bf02b793d392aca0403162Wink Saville - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); 486767a662ecde33c3979bf02b793d392aca0403162Wink Saville 487767a662ecde33c3979bf02b793d392aca0403162Wink Saville // destination address 488767a662ecde33c3979bf02b793d392aca0403162Wink Saville bo.write(daBytes, 0, daBytes.length); 489767a662ecde33c3979bf02b793d392aca0403162Wink Saville 490767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Protocol-Identifier 491767a662ecde33c3979bf02b793d392aca0403162Wink Saville bo.write(0); 492767a662ecde33c3979bf02b793d392aca0403162Wink Saville return bo; 493767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 494767a662ecde33c3979bf02b793d392aca0403162Wink Saville 495145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby private static class PduParser { 496767a662ecde33c3979bf02b793d392aca0403162Wink Saville byte pdu[]; 497767a662ecde33c3979bf02b793d392aca0403162Wink Saville int cur; 498767a662ecde33c3979bf02b793d392aca0403162Wink Saville SmsHeader userDataHeader; 499767a662ecde33c3979bf02b793d392aca0403162Wink Saville byte[] userData; 500767a662ecde33c3979bf02b793d392aca0403162Wink Saville int mUserDataSeptetPadding; 501767a662ecde33c3979bf02b793d392aca0403162Wink Saville int mUserDataSize; 502767a662ecde33c3979bf02b793d392aca0403162Wink Saville 503767a662ecde33c3979bf02b793d392aca0403162Wink Saville PduParser(byte[] pdu) { 504767a662ecde33c3979bf02b793d392aca0403162Wink Saville this.pdu = pdu; 505767a662ecde33c3979bf02b793d392aca0403162Wink Saville cur = 0; 506767a662ecde33c3979bf02b793d392aca0403162Wink Saville mUserDataSeptetPadding = 0; 507767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 508767a662ecde33c3979bf02b793d392aca0403162Wink Saville 509767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 510767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Parse and return the SC address prepended to SMS messages coming via 511767a662ecde33c3979bf02b793d392aca0403162Wink Saville * the TS 27.005 / AT interface. Returns null on invalid address 512767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 513767a662ecde33c3979bf02b793d392aca0403162Wink Saville String getSCAddress() { 514767a662ecde33c3979bf02b793d392aca0403162Wink Saville int len; 515767a662ecde33c3979bf02b793d392aca0403162Wink Saville String ret; 516767a662ecde33c3979bf02b793d392aca0403162Wink Saville 517767a662ecde33c3979bf02b793d392aca0403162Wink Saville // length of SC Address 518767a662ecde33c3979bf02b793d392aca0403162Wink Saville len = getByte(); 519767a662ecde33c3979bf02b793d392aca0403162Wink Saville 520767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (len == 0) { 521767a662ecde33c3979bf02b793d392aca0403162Wink Saville // no SC address 522767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret = null; 523767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 524767a662ecde33c3979bf02b793d392aca0403162Wink Saville // SC address 525767a662ecde33c3979bf02b793d392aca0403162Wink Saville try { 526767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret = PhoneNumberUtils 527767a662ecde33c3979bf02b793d392aca0403162Wink Saville .calledPartyBCDToString(pdu, cur, len); 528767a662ecde33c3979bf02b793d392aca0403162Wink Saville } catch (RuntimeException tr) { 529767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.d(LOG_TAG, "invalid SC address: ", tr); 530767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret = null; 531767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 532767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 533767a662ecde33c3979bf02b793d392aca0403162Wink Saville 534767a662ecde33c3979bf02b793d392aca0403162Wink Saville cur += len; 535767a662ecde33c3979bf02b793d392aca0403162Wink Saville 536767a662ecde33c3979bf02b793d392aca0403162Wink Saville return ret; 537767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 538767a662ecde33c3979bf02b793d392aca0403162Wink Saville 539767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 540767a662ecde33c3979bf02b793d392aca0403162Wink Saville * returns non-sign-extended byte value 541767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 542767a662ecde33c3979bf02b793d392aca0403162Wink Saville int getByte() { 543767a662ecde33c3979bf02b793d392aca0403162Wink Saville return pdu[cur++] & 0xff; 544767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 545767a662ecde33c3979bf02b793d392aca0403162Wink Saville 546767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 547767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Any address except the SC address (eg, originating address) See TS 548767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 23.040 9.1.2.5 549767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 550767a662ecde33c3979bf02b793d392aca0403162Wink Saville GsmSmsAddress getAddress() { 551767a662ecde33c3979bf02b793d392aca0403162Wink Saville GsmSmsAddress ret; 552767a662ecde33c3979bf02b793d392aca0403162Wink Saville 553767a662ecde33c3979bf02b793d392aca0403162Wink Saville // "The Address-Length field is an integer representation of 554145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby // the number field, i.e. excludes any semi-octet containing only 555767a662ecde33c3979bf02b793d392aca0403162Wink Saville // fill bits." 556767a662ecde33c3979bf02b793d392aca0403162Wink Saville // The TOA field is not included as part of this 557767a662ecde33c3979bf02b793d392aca0403162Wink Saville int addressLength = pdu[cur] & 0xff; 558767a662ecde33c3979bf02b793d392aca0403162Wink Saville int lengthBytes = 2 + (addressLength + 1) / 2; 559767a662ecde33c3979bf02b793d392aca0403162Wink Saville 560767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret = new GsmSmsAddress(pdu, cur, lengthBytes); 561767a662ecde33c3979bf02b793d392aca0403162Wink Saville 562767a662ecde33c3979bf02b793d392aca0403162Wink Saville cur += lengthBytes; 563767a662ecde33c3979bf02b793d392aca0403162Wink Saville 564767a662ecde33c3979bf02b793d392aca0403162Wink Saville return ret; 565767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 566767a662ecde33c3979bf02b793d392aca0403162Wink Saville 567767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 568767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Parses an SC timestamp and returns a currentTimeMillis()-style 569767a662ecde33c3979bf02b793d392aca0403162Wink Saville * timestamp 570767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 571767a662ecde33c3979bf02b793d392aca0403162Wink Saville 572767a662ecde33c3979bf02b793d392aca0403162Wink Saville long getSCTimestampMillis() { 573767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Service-Centre-Time-Stamp 5749688c6046fdbf6a24e3541bd6342995b4605fd5dWink Saville int year = IccUtils.gsmBcdByteToInt(pdu[cur++]); 5759688c6046fdbf6a24e3541bd6342995b4605fd5dWink Saville int month = IccUtils.gsmBcdByteToInt(pdu[cur++]); 5769688c6046fdbf6a24e3541bd6342995b4605fd5dWink Saville int day = IccUtils.gsmBcdByteToInt(pdu[cur++]); 5779688c6046fdbf6a24e3541bd6342995b4605fd5dWink Saville int hour = IccUtils.gsmBcdByteToInt(pdu[cur++]); 5789688c6046fdbf6a24e3541bd6342995b4605fd5dWink Saville int minute = IccUtils.gsmBcdByteToInt(pdu[cur++]); 5799688c6046fdbf6a24e3541bd6342995b4605fd5dWink Saville int second = IccUtils.gsmBcdByteToInt(pdu[cur++]); 580767a662ecde33c3979bf02b793d392aca0403162Wink Saville 581767a662ecde33c3979bf02b793d392aca0403162Wink Saville // For the timezone, the most significant bit of the 582145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby // least significant nibble is the sign byte 583767a662ecde33c3979bf02b793d392aca0403162Wink Saville // (meaning the max range of this field is 79 quarter-hours, 584767a662ecde33c3979bf02b793d392aca0403162Wink Saville // which is more than enough) 585767a662ecde33c3979bf02b793d392aca0403162Wink Saville 586767a662ecde33c3979bf02b793d392aca0403162Wink Saville byte tzByte = pdu[cur++]; 587767a662ecde33c3979bf02b793d392aca0403162Wink Saville 588767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Mask out sign bit. 5899688c6046fdbf6a24e3541bd6342995b4605fd5dWink Saville int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08))); 590767a662ecde33c3979bf02b793d392aca0403162Wink Saville 5919688c6046fdbf6a24e3541bd6342995b4605fd5dWink Saville timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset; 592767a662ecde33c3979bf02b793d392aca0403162Wink Saville 593767a662ecde33c3979bf02b793d392aca0403162Wink Saville Time time = new Time(Time.TIMEZONE_UTC); 594767a662ecde33c3979bf02b793d392aca0403162Wink Saville 595767a662ecde33c3979bf02b793d392aca0403162Wink Saville // It's 2006. Should I really support years < 2000? 596767a662ecde33c3979bf02b793d392aca0403162Wink Saville time.year = year >= 90 ? year + 1900 : year + 2000; 597767a662ecde33c3979bf02b793d392aca0403162Wink Saville time.month = month - 1; 598767a662ecde33c3979bf02b793d392aca0403162Wink Saville time.monthDay = day; 599767a662ecde33c3979bf02b793d392aca0403162Wink Saville time.hour = hour; 600767a662ecde33c3979bf02b793d392aca0403162Wink Saville time.minute = minute; 601767a662ecde33c3979bf02b793d392aca0403162Wink Saville time.second = second; 602767a662ecde33c3979bf02b793d392aca0403162Wink Saville 603767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Timezone offset is in quarter hours. 604767a662ecde33c3979bf02b793d392aca0403162Wink Saville return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); 605767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 606767a662ecde33c3979bf02b793d392aca0403162Wink Saville 607767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 608767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Pulls the user data out of the PDU, and separates the payload from 609767a662ecde33c3979bf02b793d392aca0403162Wink Saville * the header if there is one. 610767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 611767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param hasUserDataHeader true if there is a user data header 612767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param dataInSeptets true if the data payload is in septets instead 613767a662ecde33c3979bf02b793d392aca0403162Wink Saville * of octets 614767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @return the number of septets or octets in the user data payload 615767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 616767a662ecde33c3979bf02b793d392aca0403162Wink Saville int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) { 617767a662ecde33c3979bf02b793d392aca0403162Wink Saville int offset = cur; 618767a662ecde33c3979bf02b793d392aca0403162Wink Saville int userDataLength = pdu[offset++] & 0xff; 619767a662ecde33c3979bf02b793d392aca0403162Wink Saville int headerSeptets = 0; 620faf4413dffdc9079683b951736088ff2a01073a4jsh int userDataHeaderLength = 0; 621767a662ecde33c3979bf02b793d392aca0403162Wink Saville 622767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (hasUserDataHeader) { 623faf4413dffdc9079683b951736088ff2a01073a4jsh userDataHeaderLength = pdu[offset++] & 0xff; 624767a662ecde33c3979bf02b793d392aca0403162Wink Saville 625767a662ecde33c3979bf02b793d392aca0403162Wink Saville byte[] udh = new byte[userDataHeaderLength]; 626767a662ecde33c3979bf02b793d392aca0403162Wink Saville System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength); 62764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink userDataHeader = SmsHeader.fromByteArray(udh); 628767a662ecde33c3979bf02b793d392aca0403162Wink Saville offset += userDataHeaderLength; 629767a662ecde33c3979bf02b793d392aca0403162Wink Saville 630767a662ecde33c3979bf02b793d392aca0403162Wink Saville int headerBits = (userDataHeaderLength + 1) * 8; 631767a662ecde33c3979bf02b793d392aca0403162Wink Saville headerSeptets = headerBits / 7; 632767a662ecde33c3979bf02b793d392aca0403162Wink Saville headerSeptets += (headerBits % 7) > 0 ? 1 : 0; 633767a662ecde33c3979bf02b793d392aca0403162Wink Saville mUserDataSeptetPadding = (headerSeptets * 7) - headerBits; 634767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 635767a662ecde33c3979bf02b793d392aca0403162Wink Saville 636faf4413dffdc9079683b951736088ff2a01073a4jsh int bufferLen; 637faf4413dffdc9079683b951736088ff2a01073a4jsh if (dataInSeptets) { 638faf4413dffdc9079683b951736088ff2a01073a4jsh /* 639faf4413dffdc9079683b951736088ff2a01073a4jsh * Here we just create the user data length to be the remainder of 640faf4413dffdc9079683b951736088ff2a01073a4jsh * the pdu minus the user data header, since userDataLength means 641145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby * the number of uncompressed septets. 642faf4413dffdc9079683b951736088ff2a01073a4jsh */ 643faf4413dffdc9079683b951736088ff2a01073a4jsh bufferLen = pdu.length - offset; 644faf4413dffdc9079683b951736088ff2a01073a4jsh } else { 645faf4413dffdc9079683b951736088ff2a01073a4jsh /* 646faf4413dffdc9079683b951736088ff2a01073a4jsh * userDataLength is the count of octets, so just subtract the 647faf4413dffdc9079683b951736088ff2a01073a4jsh * user data header. 648faf4413dffdc9079683b951736088ff2a01073a4jsh */ 649faf4413dffdc9079683b951736088ff2a01073a4jsh bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0); 650faf4413dffdc9079683b951736088ff2a01073a4jsh if (bufferLen < 0) { 651faf4413dffdc9079683b951736088ff2a01073a4jsh bufferLen = 0; 652faf4413dffdc9079683b951736088ff2a01073a4jsh } 653faf4413dffdc9079683b951736088ff2a01073a4jsh } 654faf4413dffdc9079683b951736088ff2a01073a4jsh 655faf4413dffdc9079683b951736088ff2a01073a4jsh userData = new byte[bufferLen]; 656767a662ecde33c3979bf02b793d392aca0403162Wink Saville System.arraycopy(pdu, offset, userData, 0, userData.length); 657767a662ecde33c3979bf02b793d392aca0403162Wink Saville cur = offset; 658767a662ecde33c3979bf02b793d392aca0403162Wink Saville 659767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (dataInSeptets) { 660767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Return the number of septets 661faf4413dffdc9079683b951736088ff2a01073a4jsh int count = userDataLength - headerSeptets; 662faf4413dffdc9079683b951736088ff2a01073a4jsh // If count < 0, return 0 (means UDL was probably incorrect) 663faf4413dffdc9079683b951736088ff2a01073a4jsh return count < 0 ? 0 : count; 664767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 665767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Return the number of octets 666767a662ecde33c3979bf02b793d392aca0403162Wink Saville return userData.length; 667767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 668767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 669767a662ecde33c3979bf02b793d392aca0403162Wink Saville 670767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 671767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Returns the user data payload, not including the headers 672767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 673767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @return the user data payload, not including the headers 674767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 675767a662ecde33c3979bf02b793d392aca0403162Wink Saville byte[] getUserData() { 676767a662ecde33c3979bf02b793d392aca0403162Wink Saville return userData; 677767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 678767a662ecde33c3979bf02b793d392aca0403162Wink Saville 679767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 680145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby * Returns the number of padding bits at the beginning of the user data 681767a662ecde33c3979bf02b793d392aca0403162Wink Saville * array before the start of the septets. 682767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 683145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby * @return the number of padding bits at the beginning of the user data 684767a662ecde33c3979bf02b793d392aca0403162Wink Saville * array before the start of the septets 685767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 686767a662ecde33c3979bf02b793d392aca0403162Wink Saville int getUserDataSeptetPadding() { 687767a662ecde33c3979bf02b793d392aca0403162Wink Saville return mUserDataSeptetPadding; 688767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 689767a662ecde33c3979bf02b793d392aca0403162Wink Saville 690767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 691767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Returns an object representing the user data headers 692767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 693767a662ecde33c3979bf02b793d392aca0403162Wink Saville * {@hide} 694767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 695767a662ecde33c3979bf02b793d392aca0403162Wink Saville SmsHeader getUserDataHeader() { 696767a662ecde33c3979bf02b793d392aca0403162Wink Saville return userDataHeader; 697767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 698767a662ecde33c3979bf02b793d392aca0403162Wink Saville 699767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 700b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby * Interprets the user data payload as packed GSM 7bit characters, and 701767a662ecde33c3979bf02b793d392aca0403162Wink Saville * decodes them into a String. 702767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 703767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param septetCount the number of septets in the user data payload 704767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @return a String with the decoded characters 705767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 706b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby String getUserDataGSM7Bit(int septetCount, int languageTable, 707b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby int languageShiftTable) { 708767a662ecde33c3979bf02b793d392aca0403162Wink Saville String ret; 709767a662ecde33c3979bf02b793d392aca0403162Wink Saville 710767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount, 711b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby mUserDataSeptetPadding, languageTable, languageShiftTable); 712767a662ecde33c3979bf02b793d392aca0403162Wink Saville 713767a662ecde33c3979bf02b793d392aca0403162Wink Saville cur += (septetCount * 7) / 8; 714767a662ecde33c3979bf02b793d392aca0403162Wink Saville 715767a662ecde33c3979bf02b793d392aca0403162Wink Saville return ret; 716767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 717767a662ecde33c3979bf02b793d392aca0403162Wink Saville 718767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 719767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Interprets the user data payload as UCS2 characters, and 720767a662ecde33c3979bf02b793d392aca0403162Wink Saville * decodes them into a String. 721767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 722767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param byteCount the number of bytes in the user data payload 723767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @return a String with the decoded characters 724767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 725767a662ecde33c3979bf02b793d392aca0403162Wink Saville String getUserDataUCS2(int byteCount) { 726767a662ecde33c3979bf02b793d392aca0403162Wink Saville String ret; 727767a662ecde33c3979bf02b793d392aca0403162Wink Saville 728767a662ecde33c3979bf02b793d392aca0403162Wink Saville try { 729767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret = new String(pdu, cur, byteCount, "utf-16"); 730767a662ecde33c3979bf02b793d392aca0403162Wink Saville } catch (UnsupportedEncodingException ex) { 731767a662ecde33c3979bf02b793d392aca0403162Wink Saville ret = ""; 732767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); 733767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 734767a662ecde33c3979bf02b793d392aca0403162Wink Saville 735767a662ecde33c3979bf02b793d392aca0403162Wink Saville cur += byteCount; 736767a662ecde33c3979bf02b793d392aca0403162Wink Saville return ret; 737767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 738767a662ecde33c3979bf02b793d392aca0403162Wink Saville 739b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee /** 740b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee * Interprets the user data payload as KSC-5601 characters, and 741b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee * decodes them into a String. 742b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee * 743b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee * @param byteCount the number of bytes in the user data payload 744b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee * @return a String with the decoded characters 745b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee */ 746b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee String getUserDataKSC5601(int byteCount) { 747b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee String ret; 748b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee 749b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee try { 750b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee ret = new String(pdu, cur, byteCount, "KSC5601"); 751b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee } catch (UnsupportedEncodingException ex) { 752b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee ret = ""; 753b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); 754b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee } 755b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee 756b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee cur += byteCount; 757b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee return ret; 758b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee } 759b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee 760767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean moreDataPresent() { 761767a662ecde33c3979bf02b793d392aca0403162Wink Saville return (pdu.length > cur); 762767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 763767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 764767a662ecde33c3979bf02b793d392aca0403162Wink Saville 765a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink /** 766a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink * Calculate the number of septets needed to encode the message. 767a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink * 768fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink * @param msgBody the message to encode 769fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink * @param use7bitOnly ignore (but still count) illegal characters if true 770fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink * @return TextEncodingDetails 771a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink */ 772fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink public static TextEncodingDetails calculateLength(CharSequence msgBody, 773fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink boolean use7bitOnly) { 774b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(msgBody, use7bitOnly); 775b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby if (ted == null) { 776b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby ted = new TextEncodingDetails(); 777fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink int octets = msgBody.length() * 2; 778fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink ted.codeUnitCount = msgBody.length(); 779fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink if (octets > MAX_USER_DATA_BYTES) { 78017f616823a562ceb3a008f91e05d43bc56d37caeJake Hamby ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) / 78117f616823a562ceb3a008f91e05d43bc56d37caeJake Hamby MAX_USER_DATA_BYTES_WITH_HEADER; 78217f616823a562ceb3a008f91e05d43bc56d37caeJake Hamby ted.codeUnitsRemaining = ((ted.msgCount * 78317f616823a562ceb3a008f91e05d43bc56d37caeJake Hamby MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2; 784fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink } else { 785fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink ted.msgCount = 1; 786fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2; 787fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink } 788fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink ted.codeUnitSize = ENCODING_16BIT; 789a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink } 790fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink return ted; 791a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink } 792a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink 793767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 794145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 795767a662ecde33c3979bf02b793d392aca0403162Wink Saville public int getProtocolIdentifier() { 796767a662ecde33c3979bf02b793d392aca0403162Wink Saville return protocolIdentifier; 797767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 798767a662ecde33c3979bf02b793d392aca0403162Wink Saville 799ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby /** 800ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * Returns the TP-Data-Coding-Scheme byte, for acknowledgement of SMS-PP download messages. 801ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * @return the TP-DCS field of the SMS header 802ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby */ 803ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby int getDataCodingScheme() { 804ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby return dataCodingScheme; 805ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby } 806ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby 807767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 808145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 809767a662ecde33c3979bf02b793d392aca0403162Wink Saville public boolean isReplace() { 810767a662ecde33c3979bf02b793d392aca0403162Wink Saville return (protocolIdentifier & 0xc0) == 0x40 811767a662ecde33c3979bf02b793d392aca0403162Wink Saville && (protocolIdentifier & 0x3f) > 0 812767a662ecde33c3979bf02b793d392aca0403162Wink Saville && (protocolIdentifier & 0x3f) < 8; 813767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 814767a662ecde33c3979bf02b793d392aca0403162Wink Saville 815767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 816145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 817767a662ecde33c3979bf02b793d392aca0403162Wink Saville public boolean isCphsMwiMessage() { 818767a662ecde33c3979bf02b793d392aca0403162Wink Saville return ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear() 819767a662ecde33c3979bf02b793d392aca0403162Wink Saville || ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); 820767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 821767a662ecde33c3979bf02b793d392aca0403162Wink Saville 822767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 823145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 824767a662ecde33c3979bf02b793d392aca0403162Wink Saville public boolean isMWIClearMessage() { 825b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby if (isMwi && !mwiSense) { 826767a662ecde33c3979bf02b793d392aca0403162Wink Saville return true; 827767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 828767a662ecde33c3979bf02b793d392aca0403162Wink Saville 829767a662ecde33c3979bf02b793d392aca0403162Wink Saville return originatingAddress != null 830767a662ecde33c3979bf02b793d392aca0403162Wink Saville && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear(); 831767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 832767a662ecde33c3979bf02b793d392aca0403162Wink Saville 833767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 834145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 835767a662ecde33c3979bf02b793d392aca0403162Wink Saville public boolean isMWISetMessage() { 836b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby if (isMwi && mwiSense) { 837767a662ecde33c3979bf02b793d392aca0403162Wink Saville return true; 838767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 839767a662ecde33c3979bf02b793d392aca0403162Wink Saville 840767a662ecde33c3979bf02b793d392aca0403162Wink Saville return originatingAddress != null 841767a662ecde33c3979bf02b793d392aca0403162Wink Saville && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); 842767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 843767a662ecde33c3979bf02b793d392aca0403162Wink Saville 844767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 845145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 846767a662ecde33c3979bf02b793d392aca0403162Wink Saville public boolean isMwiDontStore() { 847767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (isMwi && mwiDontStore) { 848767a662ecde33c3979bf02b793d392aca0403162Wink Saville return true; 849767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 850767a662ecde33c3979bf02b793d392aca0403162Wink Saville 851767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (isCphsMwiMessage()) { 852767a662ecde33c3979bf02b793d392aca0403162Wink Saville // See CPHS 4.2 Section B.4.2.1 853767a662ecde33c3979bf02b793d392aca0403162Wink Saville // If the user data is a single space char, do not store 854767a662ecde33c3979bf02b793d392aca0403162Wink Saville // the message. Otherwise, store and display as usual 855767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (" ".equals(getMessageBody())) { 856767a662ecde33c3979bf02b793d392aca0403162Wink Saville ; 857767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 858767a662ecde33c3979bf02b793d392aca0403162Wink Saville return true; 859767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 860767a662ecde33c3979bf02b793d392aca0403162Wink Saville 861767a662ecde33c3979bf02b793d392aca0403162Wink Saville return false; 862767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 863767a662ecde33c3979bf02b793d392aca0403162Wink Saville 864767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 865145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 866767a662ecde33c3979bf02b793d392aca0403162Wink Saville public int getStatus() { 867767a662ecde33c3979bf02b793d392aca0403162Wink Saville return status; 868767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 869767a662ecde33c3979bf02b793d392aca0403162Wink Saville 870767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 871145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 872767a662ecde33c3979bf02b793d392aca0403162Wink Saville public boolean isStatusReportMessage() { 873767a662ecde33c3979bf02b793d392aca0403162Wink Saville return isStatusReportMessage; 874767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 875767a662ecde33c3979bf02b793d392aca0403162Wink Saville 876767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** {@inheritDoc} */ 877145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 878767a662ecde33c3979bf02b793d392aca0403162Wink Saville public boolean isReplyPathPresent() { 879767a662ecde33c3979bf02b793d392aca0403162Wink Saville return replyPathPresent; 880767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 881767a662ecde33c3979bf02b793d392aca0403162Wink Saville 882767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 883145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6] 884767a662ecde33c3979bf02b793d392aca0403162Wink Saville * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: 885767a662ecde33c3979bf02b793d392aca0403162Wink Saville * ME/TA converts each octet of TP data unit into two IRA character long 886145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby * hex number (e.g. octet with integer value 42 is presented to TE as two 887767a662ecde33c3979bf02b793d392aca0403162Wink Saville * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, 888767a662ecde33c3979bf02b793d392aca0403162Wink Saville * something else... 889767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 890767a662ecde33c3979bf02b793d392aca0403162Wink Saville private void parsePdu(byte[] pdu) { 891767a662ecde33c3979bf02b793d392aca0403162Wink Saville mPdu = pdu; 892145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby // Log.d(LOG_TAG, "raw sms message:"); 893767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Log.d(LOG_TAG, s); 894767a662ecde33c3979bf02b793d392aca0403162Wink Saville 895767a662ecde33c3979bf02b793d392aca0403162Wink Saville PduParser p = new PduParser(pdu); 896767a662ecde33c3979bf02b793d392aca0403162Wink Saville 897767a662ecde33c3979bf02b793d392aca0403162Wink Saville scAddress = p.getSCAddress(); 898767a662ecde33c3979bf02b793d392aca0403162Wink Saville 899767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (scAddress != null) { 90043a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) Log.d(LOG_TAG, "SMS SC address: " + scAddress); 901767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 902767a662ecde33c3979bf02b793d392aca0403162Wink Saville 903767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TODO(mkf) support reply path, user data header indicator 904767a662ecde33c3979bf02b793d392aca0403162Wink Saville 905767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Message-Type-Indicator 906767a662ecde33c3979bf02b793d392aca0403162Wink Saville // 9.2.3 907767a662ecde33c3979bf02b793d392aca0403162Wink Saville int firstByte = p.getByte(); 908767a662ecde33c3979bf02b793d392aca0403162Wink Saville 909767a662ecde33c3979bf02b793d392aca0403162Wink Saville mti = firstByte & 0x3; 910767a662ecde33c3979bf02b793d392aca0403162Wink Saville switch (mti) { 911767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Message-Type-Indicator 912767a662ecde33c3979bf02b793d392aca0403162Wink Saville // 9.2.3 913767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 0: 91418804b3fe4133e4e5c29118eac9dc1d426220db3Alex Yakavenka case 3: //GSM 03.40 9.2.3.1: MTI == 3 is Reserved. 91518804b3fe4133e4e5c29118eac9dc1d426220db3Alex Yakavenka //This should be processed in the same way as MTI == 0 (Deliver) 916767a662ecde33c3979bf02b793d392aca0403162Wink Saville parseSmsDeliver(p, firstByte); 917767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 918767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 2: 919767a662ecde33c3979bf02b793d392aca0403162Wink Saville parseSmsStatusReport(p, firstByte); 920767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 921767a662ecde33c3979bf02b793d392aca0403162Wink Saville default: 922767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TODO(mkf) the rest of these 923767a662ecde33c3979bf02b793d392aca0403162Wink Saville throw new RuntimeException("Unsupported message type"); 924767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 925767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 926767a662ecde33c3979bf02b793d392aca0403162Wink Saville 927767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 928767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Parses a SMS-STATUS-REPORT message. 929767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 930767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param p A PduParser, cued past the first byte. 931767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param firstByte The first byte of the PDU, which contains MTI, etc. 932767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 933767a662ecde33c3979bf02b793d392aca0403162Wink Saville private void parseSmsStatusReport(PduParser p, int firstByte) { 934767a662ecde33c3979bf02b793d392aca0403162Wink Saville isStatusReportMessage = true; 935767a662ecde33c3979bf02b793d392aca0403162Wink Saville 936767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Status-Report-Qualifier bit == 0 for SUBMIT 937767a662ecde33c3979bf02b793d392aca0403162Wink Saville forSubmit = (firstByte & 0x20) == 0x00; 938767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Message-Reference 939767a662ecde33c3979bf02b793d392aca0403162Wink Saville messageRef = p.getByte(); 940767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Recipient-Address 941767a662ecde33c3979bf02b793d392aca0403162Wink Saville recipientAddress = p.getAddress(); 942767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Service-Centre-Time-Stamp 943767a662ecde33c3979bf02b793d392aca0403162Wink Saville scTimeMillis = p.getSCTimestampMillis(); 944767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Discharge-Time 945767a662ecde33c3979bf02b793d392aca0403162Wink Saville dischargeTimeMillis = p.getSCTimestampMillis(); 946767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Status 947767a662ecde33c3979bf02b793d392aca0403162Wink Saville status = p.getByte(); 948767a662ecde33c3979bf02b793d392aca0403162Wink Saville 949767a662ecde33c3979bf02b793d392aca0403162Wink Saville // The following are optional fields that may or may not be present. 950767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (p.moreDataPresent()) { 951767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Parameter-Indicator 952767a662ecde33c3979bf02b793d392aca0403162Wink Saville int extraParams = p.getByte(); 953767a662ecde33c3979bf02b793d392aca0403162Wink Saville int moreExtraParams = extraParams; 954767a662ecde33c3979bf02b793d392aca0403162Wink Saville while ((moreExtraParams & 0x80) != 0) { 955767a662ecde33c3979bf02b793d392aca0403162Wink Saville // We only know how to parse a few extra parameters, all 956767a662ecde33c3979bf02b793d392aca0403162Wink Saville // indicated in the first TP-PI octet, so skip over any 957767a662ecde33c3979bf02b793d392aca0403162Wink Saville // additional TP-PI octets. 958767a662ecde33c3979bf02b793d392aca0403162Wink Saville moreExtraParams = p.getByte(); 959767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 960767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Protocol-Identifier 961767a662ecde33c3979bf02b793d392aca0403162Wink Saville if ((extraParams & 0x01) != 0) { 962767a662ecde33c3979bf02b793d392aca0403162Wink Saville protocolIdentifier = p.getByte(); 963767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 964767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Data-Coding-Scheme 965767a662ecde33c3979bf02b793d392aca0403162Wink Saville if ((extraParams & 0x02) != 0) { 966767a662ecde33c3979bf02b793d392aca0403162Wink Saville dataCodingScheme = p.getByte(); 967767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 968767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-User-Data-Length (implies existence of TP-User-Data) 969767a662ecde33c3979bf02b793d392aca0403162Wink Saville if ((extraParams & 0x04) != 0) { 970767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; 971767a662ecde33c3979bf02b793d392aca0403162Wink Saville parseUserData(p, hasUserDataHeader); 972767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 973767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 974767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 975767a662ecde33c3979bf02b793d392aca0403162Wink Saville 976767a662ecde33c3979bf02b793d392aca0403162Wink Saville private void parseSmsDeliver(PduParser p, int firstByte) { 977767a662ecde33c3979bf02b793d392aca0403162Wink Saville replyPathPresent = (firstByte & 0x80) == 0x80; 978767a662ecde33c3979bf02b793d392aca0403162Wink Saville 979767a662ecde33c3979bf02b793d392aca0403162Wink Saville originatingAddress = p.getAddress(); 980767a662ecde33c3979bf02b793d392aca0403162Wink Saville 981767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (originatingAddress != null) { 98243a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) Log.v(LOG_TAG, "SMS originating address: " 983767a662ecde33c3979bf02b793d392aca0403162Wink Saville + originatingAddress.address); 984767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 985767a662ecde33c3979bf02b793d392aca0403162Wink Saville 986767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Protocol-Identifier (TP-PID) 987767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TS 23.040 9.2.3.9 988767a662ecde33c3979bf02b793d392aca0403162Wink Saville protocolIdentifier = p.getByte(); 989767a662ecde33c3979bf02b793d392aca0403162Wink Saville 990767a662ecde33c3979bf02b793d392aca0403162Wink Saville // TP-Data-Coding-Scheme 991767a662ecde33c3979bf02b793d392aca0403162Wink Saville // see TS 23.038 992767a662ecde33c3979bf02b793d392aca0403162Wink Saville dataCodingScheme = p.getByte(); 993767a662ecde33c3979bf02b793d392aca0403162Wink Saville 99443a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) { 995767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.v(LOG_TAG, "SMS TP-PID:" + protocolIdentifier 996767a662ecde33c3979bf02b793d392aca0403162Wink Saville + " data coding scheme: " + dataCodingScheme); 997767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 998767a662ecde33c3979bf02b793d392aca0403162Wink Saville 999767a662ecde33c3979bf02b793d392aca0403162Wink Saville scTimeMillis = p.getSCTimestampMillis(); 1000767a662ecde33c3979bf02b793d392aca0403162Wink Saville 100143a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); 1002767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1003767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; 1004767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1005767a662ecde33c3979bf02b793d392aca0403162Wink Saville parseUserData(p, hasUserDataHeader); 1006767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1007767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1008767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 1009767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Parses the User Data of an SMS. 1010767a662ecde33c3979bf02b793d392aca0403162Wink Saville * 1011767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param p The current PduParser. 1012767a662ecde33c3979bf02b793d392aca0403162Wink Saville * @param hasUserDataHeader Indicates whether a header is present in the 1013767a662ecde33c3979bf02b793d392aca0403162Wink Saville * User Data. 1014767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 1015767a662ecde33c3979bf02b793d392aca0403162Wink Saville private void parseUserData(PduParser p, boolean hasUserDataHeader) { 1016767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean hasMessageClass = false; 1017767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean userDataCompressed = false; 1018767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1019767a662ecde33c3979bf02b793d392aca0403162Wink Saville int encodingType = ENCODING_UNKNOWN; 1020767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1021767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Look up the data encoding scheme 1022767a662ecde33c3979bf02b793d392aca0403162Wink Saville if ((dataCodingScheme & 0x80) == 0) { 1023767a662ecde33c3979bf02b793d392aca0403162Wink Saville // Bits 7..4 == 0xxx 1024767a662ecde33c3979bf02b793d392aca0403162Wink Saville automaticDeletion = (0 != (dataCodingScheme & 0x40)); 1025767a662ecde33c3979bf02b793d392aca0403162Wink Saville userDataCompressed = (0 != (dataCodingScheme & 0x20)); 1026767a662ecde33c3979bf02b793d392aca0403162Wink Saville hasMessageClass = (0 != (dataCodingScheme & 0x10)); 1027767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1028767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (userDataCompressed) { 1029767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.w(LOG_TAG, "4 - Unsupported SMS data coding scheme " 1030767a662ecde33c3979bf02b793d392aca0403162Wink Saville + "(compression) " + (dataCodingScheme & 0xff)); 1031767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 1032767a662ecde33c3979bf02b793d392aca0403162Wink Saville switch ((dataCodingScheme >> 2) & 0x3) { 1033767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 0: // GSM 7 bit default alphabet 1034767a662ecde33c3979bf02b793d392aca0403162Wink Saville encodingType = ENCODING_7BIT; 1035767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1036767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1037767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 2: // UCS 2 (16bit) 1038767a662ecde33c3979bf02b793d392aca0403162Wink Saville encodingType = ENCODING_16BIT; 1039767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1040767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1041767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 1: // 8 bit data 1042767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 3: // reserved 1043767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " 1044767a662ecde33c3979bf02b793d392aca0403162Wink Saville + (dataCodingScheme & 0xff)); 1045767a662ecde33c3979bf02b793d392aca0403162Wink Saville encodingType = ENCODING_8BIT; 1046767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1047767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1048767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1049767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else if ((dataCodingScheme & 0xf0) == 0xf0) { 1050767a662ecde33c3979bf02b793d392aca0403162Wink Saville automaticDeletion = false; 1051767a662ecde33c3979bf02b793d392aca0403162Wink Saville hasMessageClass = true; 1052767a662ecde33c3979bf02b793d392aca0403162Wink Saville userDataCompressed = false; 1053767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1054767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (0 == (dataCodingScheme & 0x04)) { 1055767a662ecde33c3979bf02b793d392aca0403162Wink Saville // GSM 7 bit default alphabet 1056767a662ecde33c3979bf02b793d392aca0403162Wink Saville encodingType = ENCODING_7BIT; 1057767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 1058767a662ecde33c3979bf02b793d392aca0403162Wink Saville // 8 bit data 1059767a662ecde33c3979bf02b793d392aca0403162Wink Saville encodingType = ENCODING_8BIT; 1060767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1061767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else if ((dataCodingScheme & 0xF0) == 0xC0 1062767a662ecde33c3979bf02b793d392aca0403162Wink Saville || (dataCodingScheme & 0xF0) == 0xD0 1063767a662ecde33c3979bf02b793d392aca0403162Wink Saville || (dataCodingScheme & 0xF0) == 0xE0) { 1064767a662ecde33c3979bf02b793d392aca0403162Wink Saville // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 1065767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1066767a662ecde33c3979bf02b793d392aca0403162Wink Saville // 0xC0 == 7 bit, don't store 1067767a662ecde33c3979bf02b793d392aca0403162Wink Saville // 0xD0 == 7 bit, store 1068767a662ecde33c3979bf02b793d392aca0403162Wink Saville // 0xE0 == UCS-2, store 1069767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1070767a662ecde33c3979bf02b793d392aca0403162Wink Saville if ((dataCodingScheme & 0xF0) == 0xE0) { 1071767a662ecde33c3979bf02b793d392aca0403162Wink Saville encodingType = ENCODING_16BIT; 1072767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 1073767a662ecde33c3979bf02b793d392aca0403162Wink Saville encodingType = ENCODING_7BIT; 1074767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1075767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1076767a662ecde33c3979bf02b793d392aca0403162Wink Saville userDataCompressed = false; 1077767a662ecde33c3979bf02b793d392aca0403162Wink Saville boolean active = ((dataCodingScheme & 0x08) == 0x08); 1078767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1079767a662ecde33c3979bf02b793d392aca0403162Wink Saville // bit 0x04 reserved 1080767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1081767a662ecde33c3979bf02b793d392aca0403162Wink Saville if ((dataCodingScheme & 0x03) == 0x00) { 1082767a662ecde33c3979bf02b793d392aca0403162Wink Saville isMwi = true; 1083767a662ecde33c3979bf02b793d392aca0403162Wink Saville mwiSense = active; 1084767a662ecde33c3979bf02b793d392aca0403162Wink Saville mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0); 1085767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 1086767a662ecde33c3979bf02b793d392aca0403162Wink Saville isMwi = false; 1087767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1088767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.w(LOG_TAG, "MWI for fax, email, or other " 1089767a662ecde33c3979bf02b793d392aca0403162Wink Saville + (dataCodingScheme & 0xff)); 1090767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1091b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee } else if ((dataCodingScheme & 0xC0) == 0x80) { 1092b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 1093b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee // 0x80..0xBF == Reserved coding groups 1094b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee if (dataCodingScheme == 0x84) { 1095b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee // This value used for KSC5601 by carriers in Korea. 1096b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee encodingType = ENCODING_KSC5601; 1097b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee } else { 1098b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee Log.w(LOG_TAG, "5 - Unsupported SMS data coding scheme " 1099b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee + (dataCodingScheme & 0xff)); 1100b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee } 1101767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 1102767a662ecde33c3979bf02b793d392aca0403162Wink Saville Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " 1103767a662ecde33c3979bf02b793d392aca0403162Wink Saville + (dataCodingScheme & 0xff)); 1104767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1105767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1106767a662ecde33c3979bf02b793d392aca0403162Wink Saville // set both the user data and the user data header. 1107767a662ecde33c3979bf02b793d392aca0403162Wink Saville int count = p.constructUserData(hasUserDataHeader, 1108767a662ecde33c3979bf02b793d392aca0403162Wink Saville encodingType == ENCODING_7BIT); 1109767a662ecde33c3979bf02b793d392aca0403162Wink Saville this.userData = p.getUserData(); 1110767a662ecde33c3979bf02b793d392aca0403162Wink Saville this.userDataHeader = p.getUserDataHeader(); 1111767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1112767a662ecde33c3979bf02b793d392aca0403162Wink Saville switch (encodingType) { 1113767a662ecde33c3979bf02b793d392aca0403162Wink Saville case ENCODING_UNKNOWN: 1114767a662ecde33c3979bf02b793d392aca0403162Wink Saville case ENCODING_8BIT: 1115767a662ecde33c3979bf02b793d392aca0403162Wink Saville messageBody = null; 1116767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1117767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1118767a662ecde33c3979bf02b793d392aca0403162Wink Saville case ENCODING_7BIT: 1119b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby messageBody = p.getUserDataGSM7Bit(count, 1120b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby hasUserDataHeader ? userDataHeader.languageTable : 0, 1121b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby hasUserDataHeader ? userDataHeader.languageShiftTable : 0); 1122767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1123767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1124767a662ecde33c3979bf02b793d392aca0403162Wink Saville case ENCODING_16BIT: 1125767a662ecde33c3979bf02b793d392aca0403162Wink Saville messageBody = p.getUserDataUCS2(count); 1126767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1127b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee 1128b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee case ENCODING_KSC5601: 1129b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee messageBody = p.getUserDataKSC5601(count); 1130b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee break; 1131767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1132767a662ecde33c3979bf02b793d392aca0403162Wink Saville 113343a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); 1134767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1135767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (messageBody != null) { 1136767a662ecde33c3979bf02b793d392aca0403162Wink Saville parseMessageBody(); 1137767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1138767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1139767a662ecde33c3979bf02b793d392aca0403162Wink Saville if (!hasMessageClass) { 1140767a662ecde33c3979bf02b793d392aca0403162Wink Saville messageClass = MessageClass.UNKNOWN; 1141767a662ecde33c3979bf02b793d392aca0403162Wink Saville } else { 1142767a662ecde33c3979bf02b793d392aca0403162Wink Saville switch (dataCodingScheme & 0x3) { 1143767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 0: 1144767a662ecde33c3979bf02b793d392aca0403162Wink Saville messageClass = MessageClass.CLASS_0; 1145767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1146767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 1: 1147767a662ecde33c3979bf02b793d392aca0403162Wink Saville messageClass = MessageClass.CLASS_1; 1148767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1149767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 2: 1150767a662ecde33c3979bf02b793d392aca0403162Wink Saville messageClass = MessageClass.CLASS_2; 1151767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1152767a662ecde33c3979bf02b793d392aca0403162Wink Saville case 3: 1153767a662ecde33c3979bf02b793d392aca0403162Wink Saville messageClass = MessageClass.CLASS_3; 1154767a662ecde33c3979bf02b793d392aca0403162Wink Saville break; 1155767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1156767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1157767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1158767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1159767a662ecde33c3979bf02b793d392aca0403162Wink Saville /** 1160767a662ecde33c3979bf02b793d392aca0403162Wink Saville * {@inheritDoc} 1161767a662ecde33c3979bf02b793d392aca0403162Wink Saville */ 1162145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby @Override 1163767a662ecde33c3979bf02b793d392aca0403162Wink Saville public MessageClass getMessageClass() { 1164767a662ecde33c3979bf02b793d392aca0403162Wink Saville return messageClass; 1165767a662ecde33c3979bf02b793d392aca0403162Wink Saville } 1166767a662ecde33c3979bf02b793d392aca0403162Wink Saville 1167ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby /** 1168ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * Returns true if this is a (U)SIM data download type SM. 1169ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * See 3GPP TS 31.111 section 9.1 and TS 23.040 section 9.2.3.9. 1170ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * 1171ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * @return true if this is a USIM data download message; false otherwise 1172ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby */ 1173ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby boolean isUsimDataDownload() { 1174ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby return messageClass == MessageClass.CLASS_2 && 1175ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby (protocolIdentifier == 0x7f || protocolIdentifier == 0x7c); 1176ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby } 1177767a662ecde33c3979bf02b793d392aca0403162Wink Saville} 1178