1c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/* 2c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Copyright (C) 2006 The Android Open Source Project 3c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 4c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Licensed under the Apache License, Version 2.0 (the "License"); 5c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * you may not use this file except in compliance with the License. 6c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * You may obtain a copy of the License at 7c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 8c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * http://www.apache.org/licenses/LICENSE-2.0 9c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 10c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Unless required by applicable law or agreed to in writing, software 11c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * distributed under the License is distributed on an "AS IS" BASIS, 12c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * See the License for the specific language governing permissions and 14c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * limitations under the License. 15c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 16c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 17c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepackage com.android.internal.telephony.gsm; 18c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 19c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.telephony.PhoneNumberUtils; 20c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.text.format.Time; 21ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Savilleimport android.telephony.Rlog; 22c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 23c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.EncodeException; 24c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.GsmAlphabet; 25c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; 26d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.IccUtils; 27c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SmsHeader; 28c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SmsMessageBase; 29c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 30c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport java.io.ByteArrayOutputStream; 31c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport java.io.UnsupportedEncodingException; 325ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumarimport java.text.ParseException; 33c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 34c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.MessageClass; 35c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.ENCODING_UNKNOWN; 36c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.ENCODING_7BIT; 37c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.ENCODING_8BIT; 38c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.ENCODING_16BIT; 39c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.ENCODING_KSC5601; 40c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_SEPTETS; 41c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES; 42c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER; 43c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 44c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/** 45c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * A Short Message Service message. 46c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 47c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 48c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepublic class SmsMessage extends SmsMessageBase { 49cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville static final String LOG_TAG = "SmsMessage"; 50cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville private static final boolean VDBG = false; 51c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 52c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private MessageClass messageClass; 53c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 54c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 55c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TP-Message-Type-Indicator 56c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 9.2.3 57c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 5822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville private int mMti; 59c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 60c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** TP-Protocol-Identifier (TP-PID) */ 6122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville private int mProtocolIdentifier; 62c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 63c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 64c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // see TS 23.038 6522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville private int mDataCodingScheme; 66c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 67c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Reply-Path 68c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // e.g. 23.040 9.2.2.1 6922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville private boolean mReplyPathPresent = false; 70c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 71c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** The address of the receiver. */ 7222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville private GsmSmsAddress mRecipientAddress; 73c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 74c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 75c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TP-Status - status of a previously submitted SMS. 76c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; 77c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * see TS 23.040, 9.2.3.15 for description of other possible values. 78c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 7922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville private int mStatus; 80c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 81c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 82c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TP-Status - status of a previously submitted SMS. 83c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * This field is true iff the message is a SMS-STATUS-REPORT message. 84c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 8522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville private boolean mIsStatusReportMessage = false; 86c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 87c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static class SubmitPdu extends SubmitPduBase { 88c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 89c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 90c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 91c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Create an SmsMessage from a raw PDU. 92c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 93c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SmsMessage createFromPdu(byte[] pdu) { 94c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 95c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage msg = new SmsMessage(); 96c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.parsePdu(pdu); 97c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msg; 98c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException ex) { 99ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 100c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 1011260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa } catch (OutOfMemoryError e) { 1021260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa Rlog.e(LOG_TAG, "SMS PDU parsing failed with out of memory: ", e); 1031260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa return null; 104c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 105c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 106c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 107c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 108c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 3GPP TS 23.040 9.2.3.9 specifies that Type Zero messages are indicated 109c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * by TP_PID field set to value 0x40 110c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 111c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isTypeZero() { 11222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return (mProtocolIdentifier == 0x40); 113c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 114c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 115c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 116c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the 117c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * +CMT unsolicited response (PDU mode, of course) 118c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * +CMT: [<alpha>],<length><CR><LF><pdu> 119c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 120c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Only public for debugging 121c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 122c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@hide} 123c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 124c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SmsMessage newFromCMT(String[] lines) { 125c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 126c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage msg = new SmsMessage(); 127c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.parsePdu(IccUtils.hexStringToBytes(lines[1])); 128c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msg; 129c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException ex) { 130ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 131c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 132c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 133c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 134c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 135c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** @hide */ 136c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SmsMessage newFromCDS(String line) { 137c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 138c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage msg = new SmsMessage(); 139c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.parsePdu(IccUtils.hexStringToBytes(line)); 140c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msg; 141c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException ex) { 142ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); 143c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 144c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 145c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 146c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 147c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 148c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Create an SmsMessage from an SMS EF record. 149c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 150c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param index Index of SMS record. This should be index in ArrayList 151c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * returned by SmsManager.getAllMessagesFromSim + 1. 152c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param data Record data. 153c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return An SmsMessage representing the record. 154c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 155c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @hide 156c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 157c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SmsMessage createFromEfRecord(int index, byte[] data) { 158c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 159c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage msg = new SmsMessage(); 160c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 16122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville msg.mIndexOnIcc = index; 162c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 163c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, 164c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // or STORED_UNSENT 165c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // See TS 51.011 10.5.3 166c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((data[0] & 1) == 0) { 167ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.w(LOG_TAG, 168c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville "SMS parsing failed: Trying to parse a free record"); 169c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 170c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 17122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville msg.mStatusOnIcc = data[0] & 0x07; 172c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 173c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 174c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int size = data.length - 1; 175c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 176c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Note: Data may include trailing FF's. That's OK; message 177c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // should still parse correctly. 178c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] pdu = new byte[size]; 179c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(data, 1, pdu, 0, size); 180c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.parsePdu(pdu); 181c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msg; 182c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException ex) { 183ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 184c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 185c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 186c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 187c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 188c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 189c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the 190c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * length in bytes (not hex chars) less the SMSC header 191c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 192c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static int getTPLayerLengthForPDU(String pdu) { 193c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int len = pdu.length() / 2; 194c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int smscLen = Integer.parseInt(pdu.substring(0, 2), 16); 195c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 196c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return len - smscLen - 1; 197c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 198c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 199c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 200c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get an SMS-SUBMIT PDU for a destination address and a message 201c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 202c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. Null means use default. 203c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 204c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message. 205c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns null on encode error. 206c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @hide 207c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 208c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SubmitPdu getSubmitPdu(String scAddress, 209c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String destinationAddress, String message, 210c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested, byte[] header) { 211c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header, 212c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ENCODING_UNKNOWN, 0, 0); 213c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 214c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 215c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 216c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 217c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get an SMS-SUBMIT PDU for a destination address and a message using the 218c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * specified encoding. 219c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 220c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. Null means use default. 221c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param encoding Encoding defined by constants in 222c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * com.android.internal.telephony.SmsConstants.ENCODING_* 223c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param languageTable 224c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param languageShiftTable 225c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 226c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message. 227c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns null on encode error. 228c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @hide 229c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 230c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SubmitPdu getSubmitPdu(String scAddress, 231c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String destinationAddress, String message, 232c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested, byte[] header, int encoding, 233c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int languageTable, int languageShiftTable) { 234c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 235c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Perform null parameter checks. 236c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (message == null || destinationAddress == null) { 237c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 238c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 239c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 240c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (encoding == ENCODING_UNKNOWN) { 241c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Find the best encoding to use 242c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville TextEncodingDetails ted = calculateLength(message, false); 243c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encoding = ted.codeUnitSize; 244c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville languageTable = ted.languageTable; 245c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville languageShiftTable = ted.languageShiftTable; 246c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 247c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (encoding == ENCODING_7BIT && 248c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville (languageTable != 0 || languageShiftTable != 0)) { 249c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (header != null) { 250c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader smsHeader = SmsHeader.fromByteArray(header); 251c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (smsHeader.languageTable != languageTable 252c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville || smsHeader.languageShiftTable != languageShiftTable) { 253ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.w(LOG_TAG, "Updating language table in SMS header: " 254c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + smsHeader.languageTable + " -> " + languageTable + ", " 255c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + smsHeader.languageShiftTable + " -> " + languageShiftTable); 256c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.languageTable = languageTable; 257c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.languageShiftTable = languageShiftTable; 258c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville header = SmsHeader.toByteArray(smsHeader); 259c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 260c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 261c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader smsHeader = new SmsHeader(); 262c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.languageTable = languageTable; 263c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.languageShiftTable = languageShiftTable; 264c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville header = SmsHeader.toByteArray(smsHeader); 265c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 266c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 267c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 268c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 269c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SubmitPdu ret = new SubmitPdu(); 270c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // MTI = SMS-SUBMIT, UDHI = header != null 271c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); 272c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ByteArrayOutputStream bo = getSubmitPduHead( 273c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddress, destinationAddress, mtiByte, 274c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville statusReportRequested, ret); 275c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 276c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // User Data (and length) 277c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] userData; 278c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 279c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (encoding == ENCODING_7BIT) { 280c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header, 281c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville languageTable, languageShiftTable); 282c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { //assume UCS-2 283c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 284c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = encodeUCS2(message, header); 285c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch(UnsupportedEncodingException uex) { 286ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, 287c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville "Implausible UnsupportedEncodingException ", 288c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville uex); 289c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 290c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 291c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 292c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (EncodeException ex) { 293c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Encoding to the 7-bit alphabet failed. Let's see if we can 294c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // send it as a UCS-2 encoded message 295c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 296c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = encodeUCS2(message, header); 297c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encoding = ENCODING_16BIT; 298c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch(UnsupportedEncodingException uex) { 299ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, 300c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville "Implausible UnsupportedEncodingException ", 301c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville uex); 302c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 303c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 304c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 305c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 306c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (encoding == ENCODING_7BIT) { 307c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { 308c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Message too long 309ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)"); 310c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 311c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 312c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 313c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Default encoding, uncompressed 314c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // To test writing messages to the SIM card, change this value 0x00 315c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // to 0x12, which means "bits 1 and 0 contain message class, and the 316c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // class is 2". Note that this takes effect for the sender. In other 317c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // words, messages sent by the phone with this change will end up on 318c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // the receiver's SIM card. You can then send messages to yourself 319c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (on a phone with this change) and they'll end up on the SIM card. 320c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0x00); 321c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { // assume UCS-2 322c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) { 323c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Message too long 324ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)"); 325c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 326c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 327c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 328c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // UCS-2 encoding, uncompressed 329c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0x08); 330c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 331c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 332c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (no TP-Validity-Period) 333c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(userData, 0, userData.length); 334c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret.encodedMessage = bo.toByteArray(); 335c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 336c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 337c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 338c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 339c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if necessary 340c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 341cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville * @return encoded message as UCS2 342c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @throws UnsupportedEncodingException 343c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 344c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static byte[] encodeUCS2(String message, byte[] header) 345c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville throws UnsupportedEncodingException { 346c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] userData, textPart; 347c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville textPart = message.getBytes("utf-16be"); 348c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 349c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (header != null) { 350c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Need 1 byte for UDHL 351c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = new byte[header.length + textPart.length + 1]; 352c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 353c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData[0] = (byte)header.length; 354c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(header, 0, userData, 1, header.length); 355c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length); 356c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 357c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville else { 358c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = textPart; 359c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 360c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] ret = new byte[userData.length+1]; 361c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret[0] = (byte) (userData.length & 0xff ); 362c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(userData, 0, ret, 1, userData.length); 363c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 364c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 365c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 366c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 367c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get an SMS-SUBMIT PDU for a destination address and a message 368c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 369c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. Null means use default. 370c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 371c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message. 372c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns null on encode error. 373c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 374c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SubmitPdu getSubmitPdu(String scAddress, 375c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String destinationAddress, String message, 376c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested) { 377c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 378c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); 379c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 380c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 381c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 382c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get an SMS-SUBMIT PDU for a data message to a destination address & port 383c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 384c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. null == use default 385c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param destinationAddress the address of the destination for the message 386c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param destinationPort the port to deliver the message to at the 387c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * destination 388c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param data the data for the message 389c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 390c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message. 391c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns null on encode error. 392c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 393c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SubmitPdu getSubmitPdu(String scAddress, 394c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String destinationAddress, int destinationPort, byte[] data, 395c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested) { 396c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 397c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs(); 398c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville portAddrs.destPort = destinationPort; 399c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville portAddrs.origPort = 0; 400c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville portAddrs.areEightBits = false; 401c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 402c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader smsHeader = new SmsHeader(); 403c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.portAddrs = portAddrs; 404c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 405c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] smsHeaderData = SmsHeader.toByteArray(smsHeader); 406c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 407c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((data.length + smsHeaderData.length + 1) > MAX_USER_DATA_BYTES) { 408ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "SMS data message may only contain " 409c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + (MAX_USER_DATA_BYTES - smsHeaderData.length - 1) + " bytes"); 410c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 411c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 412c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 413c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SubmitPdu ret = new SubmitPdu(); 414c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ByteArrayOutputStream bo = getSubmitPduHead( 415c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, 416c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-UDHI = true 417c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville statusReportRequested, ret); 418c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 419c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 420c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // No class, 8 bit data 421c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0x04); 422c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 423c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (no TP-Validity-Period) 424c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 425c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Total size 426c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(data.length + smsHeaderData.length + 1); 427c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 428c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // User data header 429c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(smsHeaderData.length); 430c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(smsHeaderData, 0, smsHeaderData.length); 431c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 432c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // User data 433c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(data, 0, data.length); 434c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 435c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret.encodedMessage = bo.toByteArray(); 436c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 437c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 438c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 439c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 440c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Create the beginning of a SUBMIT PDU. This is the part of the 441c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, 442c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * one of which takes a byte array and the other of which takes a 443c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * <code>String</code>. 444c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 445c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. null == use default 446c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param destinationAddress the address of the destination for the message 447c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param mtiByte 448c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param ret <code>SubmitPdu</code> containing the encoded SC 449c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message 450c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 451c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static ByteArrayOutputStream getSubmitPduHead( 452c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String scAddress, String destinationAddress, byte mtiByte, 453c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested, SubmitPdu ret) { 454c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ByteArrayOutputStream bo = new ByteArrayOutputStream( 455c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville MAX_USER_DATA_BYTES + 40); 456c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 457c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // SMSC address with length octet, or 0 458c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (scAddress == null) { 459c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret.encodedScAddress = null; 460c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 461c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( 462c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddress); 463c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 464c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 465c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Message-Type-Indicator (and friends) 466c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (statusReportRequested) { 467c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Set TP-Status-Report-Request bit. 468c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mtiByte |= 0x20; 469cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville if (VDBG) Rlog.d(LOG_TAG, "SMS status report requested"); 470c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 471c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(mtiByte); 472c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 473c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // space for TP-Message-Reference 474c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0); 475c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 476c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] daBytes; 477c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 478c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); 479c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 480c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // destination address length in BCD digits, ignoring TON byte and pad 481c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TODO Should be better. 482c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write((daBytes.length - 1) * 2 483c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); 484c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 485c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // destination address 486c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(daBytes, 0, daBytes.length); 487c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 488c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Protocol-Identifier 489c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0); 490c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return bo; 491c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 492c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 493c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static class PduParser { 49422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville byte mPdu[]; 49522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int mCur; 49622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville SmsHeader mUserDataHeader; 49722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville byte[] mUserData; 498c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int mUserDataSeptetPadding; 499c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 500c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville PduParser(byte[] pdu) { 50122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mPdu = pdu; 50222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mCur = 0; 503c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mUserDataSeptetPadding = 0; 504c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 505c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 506c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 507c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Parse and return the SC address prepended to SMS messages coming via 508c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * the TS 27.005 / AT interface. Returns null on invalid address 509c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 510c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getSCAddress() { 511c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int len; 512c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String ret; 513c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 514c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // length of SC Address 515c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville len = getByte(); 516c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 517c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (len == 0) { 518c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // no SC address 519c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = null; 520c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 521c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // SC address 522c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 523c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = PhoneNumberUtils 52422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville .calledPartyBCDToString(mPdu, mCur, len); 525c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException tr) { 526ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.d(LOG_TAG, "invalid SC address: ", tr); 527c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = null; 528c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 529c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 530c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 53122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mCur += len; 532c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 533c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 534c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 535c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 536c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 537c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * returns non-sign-extended byte value 538c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 539c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int getByte() { 54022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mPdu[mCur++] & 0xff; 541c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 542c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 543c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 544c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Any address except the SC address (eg, originating address) See TS 545c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 23.040 9.1.2.5 546c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 547c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville GsmSmsAddress getAddress() { 548c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville GsmSmsAddress ret; 549c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 550c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // "The Address-Length field is an integer representation of 551c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // the number field, i.e. excludes any semi-octet containing only 552c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // fill bits." 553c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // The TOA field is not included as part of this 55422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int addressLength = mPdu[mCur] & 0xff; 555c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int lengthBytes = 2 + (addressLength + 1) / 2; 556c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 5575ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar try { 55822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville ret = new GsmSmsAddress(mPdu, mCur, lengthBytes); 5595ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar } catch (ParseException e) { 5605ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar ret = null; 561ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa //This is caught by createFromPdu(byte[] pdu) 562ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa throw new RuntimeException(e.getMessage()); 5635ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar } 564c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 56522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mCur += lengthBytes; 566c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 567c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 568c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 569c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 570c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 571c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Parses an SC timestamp and returns a currentTimeMillis()-style 572c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * timestamp 573c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 574c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 575c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville long getSCTimestampMillis() { 576c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Service-Centre-Time-Stamp 57722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int year = IccUtils.gsmBcdByteToInt(mPdu[mCur++]); 57822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int month = IccUtils.gsmBcdByteToInt(mPdu[mCur++]); 57922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int day = IccUtils.gsmBcdByteToInt(mPdu[mCur++]); 58022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int hour = IccUtils.gsmBcdByteToInt(mPdu[mCur++]); 58122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int minute = IccUtils.gsmBcdByteToInt(mPdu[mCur++]); 58222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int second = IccUtils.gsmBcdByteToInt(mPdu[mCur++]); 583c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 584c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // For the timezone, the most significant bit of the 585c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // least significant nibble is the sign byte 586c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (meaning the max range of this field is 79 quarter-hours, 587c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // which is more than enough) 588c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 58922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville byte tzByte = mPdu[mCur++]; 590c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 591c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Mask out sign bit. 592c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08))); 593c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 594c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset; 595c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 596c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Time time = new Time(Time.TIMEZONE_UTC); 597c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 598c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // It's 2006. Should I really support years < 2000? 599c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.year = year >= 90 ? year + 1900 : year + 2000; 600c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.month = month - 1; 601c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.monthDay = day; 602c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.hour = hour; 603c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.minute = minute; 604c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.second = second; 605c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 606c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Timezone offset is in quarter hours. 607c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); 608c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 609c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 610c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 611c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Pulls the user data out of the PDU, and separates the payload from 612c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * the header if there is one. 613c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 614c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param hasUserDataHeader true if there is a user data header 615c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param dataInSeptets true if the data payload is in septets instead 616c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * of octets 617c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return the number of septets or octets in the user data payload 618c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 619c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) { 62022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int offset = mCur; 62122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int userDataLength = mPdu[offset++] & 0xff; 622c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int headerSeptets = 0; 623c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int userDataHeaderLength = 0; 624c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 625c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (hasUserDataHeader) { 62622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville userDataHeaderLength = mPdu[offset++] & 0xff; 627c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 628c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] udh = new byte[userDataHeaderLength]; 62922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville System.arraycopy(mPdu, offset, udh, 0, userDataHeaderLength); 63022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mUserDataHeader = SmsHeader.fromByteArray(udh); 631c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville offset += userDataHeaderLength; 632c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 633c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int headerBits = (userDataHeaderLength + 1) * 8; 634c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville headerSeptets = headerBits / 7; 635c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville headerSeptets += (headerBits % 7) > 0 ? 1 : 0; 636c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mUserDataSeptetPadding = (headerSeptets * 7) - headerBits; 637c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 638c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 639c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int bufferLen; 640c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (dataInSeptets) { 641c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /* 642c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Here we just create the user data length to be the remainder of 643c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * the pdu minus the user data header, since userDataLength means 644c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * the number of uncompressed septets. 645c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 64622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville bufferLen = mPdu.length - offset; 647c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 648c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /* 649c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * userDataLength is the count of octets, so just subtract the 650c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * user data header. 651c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 652c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0); 653c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (bufferLen < 0) { 654c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bufferLen = 0; 655c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 656c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 657c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 65822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mUserData = new byte[bufferLen]; 65922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville System.arraycopy(mPdu, offset, mUserData, 0, mUserData.length); 66022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mCur = offset; 661c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 662c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (dataInSeptets) { 663c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Return the number of septets 664c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int count = userDataLength - headerSeptets; 665c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // If count < 0, return 0 (means UDL was probably incorrect) 666c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return count < 0 ? 0 : count; 667c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 668c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Return the number of octets 66922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mUserData.length; 670c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 671c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 672c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 673c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 674c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns the user data payload, not including the headers 675c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 676c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return the user data payload, not including the headers 677c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 678c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] getUserData() { 67922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mUserData; 680c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 681c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 682c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 683c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns an object representing the user data headers 684c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 685c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@hide} 686c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 687c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader getUserDataHeader() { 68822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mUserDataHeader; 689c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 690c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 691c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 692c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Interprets the user data payload as packed GSM 7bit characters, and 693c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * decodes them into a String. 694c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 695c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param septetCount the number of septets in the user data payload 696c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a String with the decoded characters 697c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 698c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getUserDataGSM7Bit(int septetCount, int languageTable, 699c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int languageShiftTable) { 700c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String ret; 701c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 70222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville ret = GsmAlphabet.gsm7BitPackedToString(mPdu, mCur, septetCount, 703c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mUserDataSeptetPadding, languageTable, languageShiftTable); 704c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 70522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mCur += (septetCount * 7) / 8; 706c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 707c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 708c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 709c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 710c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 711c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Interprets the user data payload as UCS2 characters, and 712c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * decodes them into a String. 713c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 714c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param byteCount the number of bytes in the user data payload 715c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a String with the decoded characters 716c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 717c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getUserDataUCS2(int byteCount) { 718c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String ret; 719c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 720c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 72122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville ret = new String(mPdu, mCur, byteCount, "utf-16"); 722c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (UnsupportedEncodingException ex) { 723c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = ""; 724ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); 725c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 726c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 72722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mCur += byteCount; 728c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 729c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 730c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 731c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 732c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Interprets the user data payload as KSC-5601 characters, and 733c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * decodes them into a String. 734c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 735c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param byteCount the number of bytes in the user data payload 736c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a String with the decoded characters 737c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 738c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getUserDataKSC5601(int byteCount) { 739c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String ret; 740c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 741c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 74222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville ret = new String(mPdu, mCur, byteCount, "KSC5601"); 743c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (UnsupportedEncodingException ex) { 744c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = ""; 745ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); 746c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 747c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 74822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mCur += byteCount; 749c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 750c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 751c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 752c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean moreDataPresent() { 75322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return (mPdu.length > mCur); 754c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 755c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 756c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 757c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 758c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Calculate the number of septets needed to encode the message. 759c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 760c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param msgBody the message to encode 761c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param use7bitOnly ignore (but still count) illegal characters if true 762c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return TextEncodingDetails 763c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 764c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static TextEncodingDetails calculateLength(CharSequence msgBody, 765c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean use7bitOnly) { 766c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(msgBody, use7bitOnly); 767c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (ted == null) { 768c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted = new TextEncodingDetails(); 769c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int octets = msgBody.length() * 2; 770c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.codeUnitCount = msgBody.length(); 771c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (octets > MAX_USER_DATA_BYTES) { 772c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) / 773c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville MAX_USER_DATA_BYTES_WITH_HEADER; 774c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.codeUnitsRemaining = ((ted.msgCount * 775c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2; 776c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 777c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.msgCount = 1; 778c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2; 779c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 780c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.codeUnitSize = ENCODING_16BIT; 781c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 782c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ted; 783c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 784c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 785c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 786c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 787c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public int getProtocolIdentifier() { 78822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mProtocolIdentifier; 789c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 790c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 791c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 792c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns the TP-Data-Coding-Scheme byte, for acknowledgement of SMS-PP download messages. 793c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return the TP-DCS field of the SMS header 794c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 795c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int getDataCodingScheme() { 79622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mDataCodingScheme; 797c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 798c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 799c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 800c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 801c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isReplace() { 80222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return (mProtocolIdentifier & 0xc0) == 0x40 80322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville && (mProtocolIdentifier & 0x3f) > 0 80422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville && (mProtocolIdentifier & 0x3f) < 8; 805c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 806c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 807c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 808c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 809c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isCphsMwiMessage() { 81022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageClear() 81122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville || ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageSet(); 812c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 813c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 814c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 815c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 816c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isMWIClearMessage() { 81722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (mIsMwi && !mMwiSense) { 818c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 819c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 820c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 82122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mOriginatingAddress != null 82222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville && ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageClear(); 823c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 824c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 825c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 826c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 827c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isMWISetMessage() { 82822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (mIsMwi && mMwiSense) { 829c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 830c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 831c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 83222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mOriginatingAddress != null 83322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville && ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageSet(); 834c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 835c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 836c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 837c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 838c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isMwiDontStore() { 83922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (mIsMwi && mMwiDontStore) { 840c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 841c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 842c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 843c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (isCphsMwiMessage()) { 844c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // See CPHS 4.2 Section B.4.2.1 845c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // If the user data is a single space char, do not store 846c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // the message. Otherwise, store and display as usual 847c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (" ".equals(getMessageBody())) { 848945e169166e9fd4bcb145d23dffb7c7b68cd6208Björn Ekberg return true; 849c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 850c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 851c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 852c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return false; 853c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 854c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 855c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 856c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 857c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public int getStatus() { 85822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mStatus; 859c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 860c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 861c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 862c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 863c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isStatusReportMessage() { 86422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mIsStatusReportMessage; 865c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 866c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 867c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 868c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 869c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isReplyPathPresent() { 87022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mReplyPathPresent; 871c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 872c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 873c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 874c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6] 875c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: 876c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * ME/TA converts each octet of TP data unit into two IRA character long 877c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * hex number (e.g. octet with integer value 42 is presented to TE as two 878c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, 879c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * something else... 880c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 881c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void parsePdu(byte[] pdu) { 882c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mPdu = pdu; 883ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville // Rlog.d(LOG_TAG, "raw sms message:"); 884ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville // Rlog.d(LOG_TAG, s); 885c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 886c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville PduParser p = new PduParser(pdu); 887c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 88822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mScAddress = p.getSCAddress(); 889c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 89022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (mScAddress != null) { 89122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (VDBG) Rlog.d(LOG_TAG, "SMS SC address: " + mScAddress); 892c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 893c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 894c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TODO(mkf) support reply path, user data header indicator 895c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 896c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Message-Type-Indicator 897c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 9.2.3 898c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int firstByte = p.getByte(); 899c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 90022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMti = firstByte & 0x3; 90122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville switch (mMti) { 902c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Message-Type-Indicator 903c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 9.2.3 904c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 0: 905c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 3: //GSM 03.40 9.2.3.1: MTI == 3 is Reserved. 906c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville //This should be processed in the same way as MTI == 0 (Deliver) 907c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville parseSmsDeliver(p, firstByte); 908c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 9092cbcc15677797f5879cf8c907876b366b034d433Bin Li case 1: 9102cbcc15677797f5879cf8c907876b366b034d433Bin Li parseSmsSubmit(p, firstByte); 9112cbcc15677797f5879cf8c907876b366b034d433Bin Li break; 912c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 2: 913c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville parseSmsStatusReport(p, firstByte); 914c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 915c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville default: 916c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TODO(mkf) the rest of these 917c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville throw new RuntimeException("Unsupported message type"); 918c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 919c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 920c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 921c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 922c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Parses a SMS-STATUS-REPORT message. 923c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 924c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param p A PduParser, cued past the first byte. 925c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param firstByte The first byte of the PDU, which contains MTI, etc. 926c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 927c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void parseSmsStatusReport(PduParser p, int firstByte) { 92822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mIsStatusReportMessage = true; 929c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 930c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Message-Reference 93122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMessageRef = p.getByte(); 932c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Recipient-Address 93322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mRecipientAddress = p.getAddress(); 934c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Service-Centre-Time-Stamp 93522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mScTimeMillis = p.getSCTimestampMillis(); 936cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville p.getSCTimestampMillis(); 937c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Status 93822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mStatus = p.getByte(); 939c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 940c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // The following are optional fields that may or may not be present. 941c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (p.moreDataPresent()) { 942c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Parameter-Indicator 943c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int extraParams = p.getByte(); 944c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int moreExtraParams = extraParams; 945c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville while ((moreExtraParams & 0x80) != 0) { 946c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // We only know how to parse a few extra parameters, all 947c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // indicated in the first TP-PI octet, so skip over any 948c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // additional TP-PI octets. 949c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville moreExtraParams = p.getByte(); 950c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 95156c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // As per 3GPP 23.040 section 9.2.3.27 TP-Parameter-Indicator, 95256c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // only process the byte if the reserved bits (bits3 to 6) are zero. 95356c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan if ((extraParams & 0x78) == 0) { 95456c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // TP-Protocol-Identifier 95556c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan if ((extraParams & 0x01) != 0) { 95622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mProtocolIdentifier = p.getByte(); 95756c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan } 95856c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // TP-Data-Coding-Scheme 95956c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan if ((extraParams & 0x02) != 0) { 96022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mDataCodingScheme = p.getByte(); 96156c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan } 96256c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // TP-User-Data-Length (implies existence of TP-User-Data) 96356c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan if ((extraParams & 0x04) != 0) { 96456c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; 96556c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan parseUserData(p, hasUserDataHeader); 96656c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan } 967c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 968c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 969c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 970c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 971c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void parseSmsDeliver(PduParser p, int firstByte) { 97222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mReplyPathPresent = (firstByte & 0x80) == 0x80; 973c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 97422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mOriginatingAddress = p.getAddress(); 975c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 97622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (mOriginatingAddress != null) { 977cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: " 97822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville + mOriginatingAddress.address); 979c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 980c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 981c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Protocol-Identifier (TP-PID) 982c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TS 23.040 9.2.3.9 98322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mProtocolIdentifier = p.getByte(); 984c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 985c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 986c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // see TS 23.038 98722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mDataCodingScheme = p.getByte(); 988c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 989cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville if (VDBG) { 99022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville Rlog.v(LOG_TAG, "SMS TP-PID:" + mProtocolIdentifier 99122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville + " data coding scheme: " + mDataCodingScheme); 992c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 993c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 99422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mScTimeMillis = p.getSCTimestampMillis(); 995c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 99622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis); 997c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 998c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; 999c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1000c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville parseUserData(p, hasUserDataHeader); 1001c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1002c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1003c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 10042cbcc15677797f5879cf8c907876b366b034d433Bin Li * Parses a SMS-SUBMIT message. 10052cbcc15677797f5879cf8c907876b366b034d433Bin Li * 10062cbcc15677797f5879cf8c907876b366b034d433Bin Li * @param p A PduParser, cued past the first byte. 10072cbcc15677797f5879cf8c907876b366b034d433Bin Li * @param firstByte The first byte of the PDU, which contains MTI, etc. 10082cbcc15677797f5879cf8c907876b366b034d433Bin Li */ 10092cbcc15677797f5879cf8c907876b366b034d433Bin Li private void parseSmsSubmit(PduParser p, int firstByte) { 101022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mReplyPathPresent = (firstByte & 0x80) == 0x80; 10112cbcc15677797f5879cf8c907876b366b034d433Bin Li 10122cbcc15677797f5879cf8c907876b366b034d433Bin Li // TP-MR (TP-Message Reference) 101322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMessageRef = p.getByte(); 10142cbcc15677797f5879cf8c907876b366b034d433Bin Li 101522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mRecipientAddress = p.getAddress(); 10162cbcc15677797f5879cf8c907876b366b034d433Bin Li 101722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (mRecipientAddress != null) { 101822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (VDBG) Rlog.v(LOG_TAG, "SMS recipient address: " + mRecipientAddress.address); 10192cbcc15677797f5879cf8c907876b366b034d433Bin Li } 10202cbcc15677797f5879cf8c907876b366b034d433Bin Li 10212cbcc15677797f5879cf8c907876b366b034d433Bin Li // TP-Protocol-Identifier (TP-PID) 10222cbcc15677797f5879cf8c907876b366b034d433Bin Li // TS 23.040 9.2.3.9 102322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mProtocolIdentifier = p.getByte(); 10242cbcc15677797f5879cf8c907876b366b034d433Bin Li 10252cbcc15677797f5879cf8c907876b366b034d433Bin Li // TP-Data-Coding-Scheme 10262cbcc15677797f5879cf8c907876b366b034d433Bin Li // see TS 23.038 102722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mDataCodingScheme = p.getByte(); 10282cbcc15677797f5879cf8c907876b366b034d433Bin Li 1029cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville if (VDBG) { 103022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville Rlog.v(LOG_TAG, "SMS TP-PID:" + mProtocolIdentifier 103122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville + " data coding scheme: " + mDataCodingScheme); 10322cbcc15677797f5879cf8c907876b366b034d433Bin Li } 10332cbcc15677797f5879cf8c907876b366b034d433Bin Li 10342cbcc15677797f5879cf8c907876b366b034d433Bin Li // TP-Validity-Period-Format 10352cbcc15677797f5879cf8c907876b366b034d433Bin Li int validityPeriodLength = 0; 10362cbcc15677797f5879cf8c907876b366b034d433Bin Li int validityPeriodFormat = ((firstByte>>3) & 0x3); 10372cbcc15677797f5879cf8c907876b366b034d433Bin Li if (0x0 == validityPeriodFormat) /* 00, TP-VP field not present*/ 10382cbcc15677797f5879cf8c907876b366b034d433Bin Li { 10392cbcc15677797f5879cf8c907876b366b034d433Bin Li validityPeriodLength = 0; 10402cbcc15677797f5879cf8c907876b366b034d433Bin Li } 10412cbcc15677797f5879cf8c907876b366b034d433Bin Li else if (0x2 == validityPeriodFormat) /* 10, TP-VP: relative format*/ 10422cbcc15677797f5879cf8c907876b366b034d433Bin Li { 10432cbcc15677797f5879cf8c907876b366b034d433Bin Li validityPeriodLength = 1; 10442cbcc15677797f5879cf8c907876b366b034d433Bin Li } 10452cbcc15677797f5879cf8c907876b366b034d433Bin Li else /* other case, 11 or 01, TP-VP: absolute or enhanced format*/ 10462cbcc15677797f5879cf8c907876b366b034d433Bin Li { 10472cbcc15677797f5879cf8c907876b366b034d433Bin Li validityPeriodLength = 7; 10482cbcc15677797f5879cf8c907876b366b034d433Bin Li } 10492cbcc15677797f5879cf8c907876b366b034d433Bin Li 10502cbcc15677797f5879cf8c907876b366b034d433Bin Li // TP-Validity-Period is not used on phone, so just ignore it for now. 10512cbcc15677797f5879cf8c907876b366b034d433Bin Li while (validityPeriodLength-- > 0) 10522cbcc15677797f5879cf8c907876b366b034d433Bin Li { 10532cbcc15677797f5879cf8c907876b366b034d433Bin Li p.getByte(); 10542cbcc15677797f5879cf8c907876b366b034d433Bin Li } 10552cbcc15677797f5879cf8c907876b366b034d433Bin Li 10562cbcc15677797f5879cf8c907876b366b034d433Bin Li boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; 10572cbcc15677797f5879cf8c907876b366b034d433Bin Li 10582cbcc15677797f5879cf8c907876b366b034d433Bin Li parseUserData(p, hasUserDataHeader); 10592cbcc15677797f5879cf8c907876b366b034d433Bin Li } 10602cbcc15677797f5879cf8c907876b366b034d433Bin Li 10612cbcc15677797f5879cf8c907876b366b034d433Bin Li /** 1062c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Parses the User Data of an SMS. 1063c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 1064c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param p The current PduParser. 1065c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param hasUserDataHeader Indicates whether a header is present in the 1066c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * User Data. 1067c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 1068c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void parseUserData(PduParser p, boolean hasUserDataHeader) { 1069c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean hasMessageClass = false; 1070c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean userDataCompressed = false; 1071c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1072c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int encodingType = ENCODING_UNKNOWN; 1073c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1074c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Look up the data encoding scheme 107522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if ((mDataCodingScheme & 0x80) == 0) { 107622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville userDataCompressed = (0 != (mDataCodingScheme & 0x20)); 107722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville hasMessageClass = (0 != (mDataCodingScheme & 0x10)); 1078c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1079c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (userDataCompressed) { 1080ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.w(LOG_TAG, "4 - Unsupported SMS data coding scheme " 108122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville + "(compression) " + (mDataCodingScheme & 0xff)); 1082c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 108322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville switch ((mDataCodingScheme >> 2) & 0x3) { 1084c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 0: // GSM 7 bit default alphabet 1085c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_7BIT; 1086c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1087c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1088c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 2: // UCS 2 (16bit) 1089c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_16BIT; 1090c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1091c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1092c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 1: // 8 bit data 1093c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 3: // reserved 1094ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " 109522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville + (mDataCodingScheme & 0xff)); 1096c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_8BIT; 1097c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1098c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1099c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 110022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville } else if ((mDataCodingScheme & 0xf0) == 0xf0) { 1101c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville hasMessageClass = true; 1102c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userDataCompressed = false; 1103c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 110422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (0 == (mDataCodingScheme & 0x04)) { 1105c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // GSM 7 bit default alphabet 1106c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_7BIT; 1107c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1108c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 8 bit data 1109c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_8BIT; 1110c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 111122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville } else if ((mDataCodingScheme & 0xF0) == 0xC0 111222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville || (mDataCodingScheme & 0xF0) == 0xD0 111322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville || (mDataCodingScheme & 0xF0) == 0xE0) { 1114c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 1115c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1116c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 0xC0 == 7 bit, don't store 1117c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 0xD0 == 7 bit, store 1118c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 0xE0 == UCS-2, store 1119c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 112022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if ((mDataCodingScheme & 0xF0) == 0xE0) { 1121c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_16BIT; 1122c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1123c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_7BIT; 1124c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1125c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1126c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userDataCompressed = false; 112722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville boolean active = ((mDataCodingScheme & 0x08) == 0x08); 1128c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1129c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // bit 0x04 reserved 1130c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 113122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if ((mDataCodingScheme & 0x03) == 0x00) { 113222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mIsMwi = true; 113322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMwiSense = active; 113422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMwiDontStore = ((mDataCodingScheme & 0xF0) == 0xC0); 1135c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 113622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mIsMwi = false; 1137c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1138ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.w(LOG_TAG, "MWI for fax, email, or other " 113922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville + (mDataCodingScheme & 0xff)); 1140c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 114122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville } else if ((mDataCodingScheme & 0xC0) == 0x80) { 1142c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 1143c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 0x80..0xBF == Reserved coding groups 114422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (mDataCodingScheme == 0x84) { 1145c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // This value used for KSC5601 by carriers in Korea. 1146c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_KSC5601; 1147c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1148ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.w(LOG_TAG, "5 - Unsupported SMS data coding scheme " 114922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville + (mDataCodingScheme & 0xff)); 1150c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1151c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1152ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville Rlog.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " 115322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville + (mDataCodingScheme & 0xff)); 1154c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1155c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1156c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // set both the user data and the user data header. 1157c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int count = p.constructUserData(hasUserDataHeader, 1158c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType == ENCODING_7BIT); 115922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville this.mUserData = p.getUserData(); 116022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville this.mUserDataHeader = p.getUserDataHeader(); 1161c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1162c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch (encodingType) { 1163c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_UNKNOWN: 1164c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_8BIT: 116522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMessageBody = null; 1166c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1167c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1168c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_7BIT: 116922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMessageBody = p.getUserDataGSM7Bit(count, 117022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville hasUserDataHeader ? mUserDataHeader.languageTable : 0, 117122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville hasUserDataHeader ? mUserDataHeader.languageShiftTable : 0); 1172c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1173c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1174c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_16BIT: 117522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMessageBody = p.getUserDataUCS2(count); 1176c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1177c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1178c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_KSC5601: 117922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mMessageBody = p.getUserDataKSC5601(count); 1180c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1181c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1182c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 118322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (VDBG) Rlog.v(LOG_TAG, "SMS message body (raw): '" + mMessageBody + "'"); 1184c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 118522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (mMessageBody != null) { 1186c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville parseMessageBody(); 1187c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1188c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1189c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (!hasMessageClass) { 1190c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.UNKNOWN; 1191c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 119222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville switch (mDataCodingScheme & 0x3) { 1193c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 0: 1194c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.CLASS_0; 1195c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1196c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 1: 1197c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.CLASS_1; 1198c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1199c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 2: 1200c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.CLASS_2; 1201c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1202c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 3: 1203c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.CLASS_3; 1204c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1205c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1206c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1207c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1208c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1209c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 1210c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@inheritDoc} 1211c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 1212c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 1213c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public MessageClass getMessageClass() { 1214c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return messageClass; 1215c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1216c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1217c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 1218c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns true if this is a (U)SIM data download type SM. 1219c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * See 3GPP TS 31.111 section 9.1 and TS 23.040 section 9.2.3.9. 1220c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 1221c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return true if this is a USIM data download message; false otherwise 1222c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 1223c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean isUsimDataDownload() { 1224c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return messageClass == MessageClass.CLASS_2 && 122522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville (mProtocolIdentifier == 0x7f || mProtocolIdentifier == 0x7c); 1226c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1227c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville} 1228