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; 21c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.util.Log; 22c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 23c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.EncodeException; 24c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.GsmAlphabet; 25c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; 26c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.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 { 49c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville static final String LOG_TAG = "GSM"; 50c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 51c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private MessageClass messageClass; 52c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 53c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 54c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TP-Message-Type-Indicator 55c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 9.2.3 56c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 57c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private int mti; 58c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 59c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** TP-Protocol-Identifier (TP-PID) */ 60c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private int protocolIdentifier; 61c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 62c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 63c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // see TS 23.038 64c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private int dataCodingScheme; 65c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 66c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Reply-Path 67c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // e.g. 23.040 9.2.2.1 68c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private boolean replyPathPresent = false; 69c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 70c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // "Message Marked for Automatic Deletion Group" 71c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 23.038 Section 4 72c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private boolean automaticDeletion; 73c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 74c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** True if Status Report is for SMS-SUBMIT; false for SMS-COMMAND. */ 75c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private boolean forSubmit; 76c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 77c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** The address of the receiver. */ 78c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private GsmSmsAddress recipientAddress; 79c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 80c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** Time when SMS-SUBMIT was delivered from SC to MSE. */ 81c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private long dischargeTimeMillis; 82c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 83c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 84c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TP-Status - status of a previously submitted SMS. 85c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; 86c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * see TS 23.040, 9.2.3.15 for description of other possible values. 87c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 88c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private int status; 89c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 90c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 91c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TP-Status - status of a previously submitted SMS. 92c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * This field is true iff the message is a SMS-STATUS-REPORT message. 93c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 94c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private boolean isStatusReportMessage = false; 95c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 96c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static class SubmitPdu extends SubmitPduBase { 97c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 98c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 99c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 100c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Create an SmsMessage from a raw PDU. 101c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 102c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SmsMessage createFromPdu(byte[] pdu) { 103c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 104c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage msg = new SmsMessage(); 105c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.parsePdu(pdu); 106c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msg; 107c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException ex) { 108c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 109c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 110c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 111c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 112c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 113c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 114c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 3GPP TS 23.040 9.2.3.9 specifies that Type Zero messages are indicated 115c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * by TP_PID field set to value 0x40 116c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 117c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isTypeZero() { 118c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return (protocolIdentifier == 0x40); 119c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 120c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 121c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 122c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the 123c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * +CMT unsolicited response (PDU mode, of course) 124c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * +CMT: [<alpha>],<length><CR><LF><pdu> 125c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 126c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Only public for debugging 127c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 128c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@hide} 129c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 130c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SmsMessage newFromCMT(String[] lines) { 131c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 132c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage msg = new SmsMessage(); 133c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.parsePdu(IccUtils.hexStringToBytes(lines[1])); 134c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msg; 135c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException ex) { 136c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 137c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 138c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 139c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 140c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 141c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** @hide */ 142c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SmsMessage newFromCDS(String line) { 143c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 144c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage msg = new SmsMessage(); 145c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.parsePdu(IccUtils.hexStringToBytes(line)); 146c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msg; 147c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException ex) { 148c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); 149c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 150c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 151c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 152c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 153c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 154c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Create an SmsMessage from an SMS EF record. 155c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 156c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param index Index of SMS record. This should be index in ArrayList 157c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * returned by SmsManager.getAllMessagesFromSim + 1. 158c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param data Record data. 159c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return An SmsMessage representing the record. 160c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 161c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @hide 162c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 163c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SmsMessage createFromEfRecord(int index, byte[] data) { 164c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 165c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage msg = new SmsMessage(); 166c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 167c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.indexOnIcc = index; 168c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 169c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, 170c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // or STORED_UNSENT 171c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // See TS 51.011 10.5.3 172c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((data[0] & 1) == 0) { 173c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.w(LOG_TAG, 174c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville "SMS parsing failed: Trying to parse a free record"); 175c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 176c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 177c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.statusOnIcc = data[0] & 0x07; 178c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 179c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 180c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int size = data.length - 1; 181c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 182c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Note: Data may include trailing FF's. That's OK; message 183c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // should still parse correctly. 184c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] pdu = new byte[size]; 185c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(data, 1, pdu, 0, size); 186c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msg.parsePdu(pdu); 187c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msg; 188c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException ex) { 189c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); 190c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 191c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 192c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 193c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 194c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 195c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the 196c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * length in bytes (not hex chars) less the SMSC header 197c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 198c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static int getTPLayerLengthForPDU(String pdu) { 199c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int len = pdu.length() / 2; 200c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int smscLen = Integer.parseInt(pdu.substring(0, 2), 16); 201c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 202c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return len - smscLen - 1; 203c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 204c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 205c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 206c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get an SMS-SUBMIT PDU for a destination address and a message 207c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 208c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. Null means use default. 209c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 210c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message. 211c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns null on encode error. 212c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @hide 213c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 214c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SubmitPdu getSubmitPdu(String scAddress, 215c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String destinationAddress, String message, 216c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested, byte[] header) { 217c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header, 218c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ENCODING_UNKNOWN, 0, 0); 219c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 220c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 221c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 222c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 223c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get an SMS-SUBMIT PDU for a destination address and a message using the 224c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * specified encoding. 225c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 226c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. Null means use default. 227c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param encoding Encoding defined by constants in 228c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * com.android.internal.telephony.SmsConstants.ENCODING_* 229c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param languageTable 230c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param languageShiftTable 231c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 232c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message. 233c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns null on encode error. 234c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @hide 235c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 236c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SubmitPdu getSubmitPdu(String scAddress, 237c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String destinationAddress, String message, 238c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested, byte[] header, int encoding, 239c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int languageTable, int languageShiftTable) { 240c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 241c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Perform null parameter checks. 242c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (message == null || destinationAddress == null) { 243c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 244c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 245c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 246c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (encoding == ENCODING_UNKNOWN) { 247c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Find the best encoding to use 248c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville TextEncodingDetails ted = calculateLength(message, false); 249c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encoding = ted.codeUnitSize; 250c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville languageTable = ted.languageTable; 251c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville languageShiftTable = ted.languageShiftTable; 252c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 253c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (encoding == ENCODING_7BIT && 254c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville (languageTable != 0 || languageShiftTable != 0)) { 255c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (header != null) { 256c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader smsHeader = SmsHeader.fromByteArray(header); 257c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (smsHeader.languageTable != languageTable 258c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville || smsHeader.languageShiftTable != languageShiftTable) { 259c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.w(LOG_TAG, "Updating language table in SMS header: " 260c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + smsHeader.languageTable + " -> " + languageTable + ", " 261c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + smsHeader.languageShiftTable + " -> " + languageShiftTable); 262c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.languageTable = languageTable; 263c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.languageShiftTable = languageShiftTable; 264c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville header = SmsHeader.toByteArray(smsHeader); 265c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 266c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 267c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader smsHeader = new SmsHeader(); 268c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.languageTable = languageTable; 269c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.languageShiftTable = languageShiftTable; 270c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville header = SmsHeader.toByteArray(smsHeader); 271c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 272c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 273c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 274c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 275c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SubmitPdu ret = new SubmitPdu(); 276c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // MTI = SMS-SUBMIT, UDHI = header != null 277c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); 278c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ByteArrayOutputStream bo = getSubmitPduHead( 279c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddress, destinationAddress, mtiByte, 280c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville statusReportRequested, ret); 281c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 282c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // User Data (and length) 283c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] userData; 284c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 285c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (encoding == ENCODING_7BIT) { 286c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header, 287c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville languageTable, languageShiftTable); 288c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { //assume UCS-2 289c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 290c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = encodeUCS2(message, header); 291c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch(UnsupportedEncodingException uex) { 292c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, 293c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville "Implausible UnsupportedEncodingException ", 294c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville uex); 295c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 296c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 297c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 298c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (EncodeException ex) { 299c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Encoding to the 7-bit alphabet failed. Let's see if we can 300c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // send it as a UCS-2 encoded message 301c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 302c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = encodeUCS2(message, header); 303c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encoding = ENCODING_16BIT; 304c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch(UnsupportedEncodingException uex) { 305c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, 306c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville "Implausible UnsupportedEncodingException ", 307c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville uex); 308c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 309c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 310c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 311c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 312c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (encoding == ENCODING_7BIT) { 313c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { 314c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Message too long 315c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)"); 316c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 317c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 318c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 319c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Default encoding, uncompressed 320c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // To test writing messages to the SIM card, change this value 0x00 321c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // to 0x12, which means "bits 1 and 0 contain message class, and the 322c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // class is 2". Note that this takes effect for the sender. In other 323c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // words, messages sent by the phone with this change will end up on 324c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // the receiver's SIM card. You can then send messages to yourself 325c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (on a phone with this change) and they'll end up on the SIM card. 326c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0x00); 327c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { // assume UCS-2 328c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) { 329c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Message too long 330c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)"); 331c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 332c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 333c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 334c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // UCS-2 encoding, uncompressed 335c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0x08); 336c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 337c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 338c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (no TP-Validity-Period) 339c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(userData, 0, userData.length); 340c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret.encodedMessage = bo.toByteArray(); 341c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 342c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 343c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 344c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 345c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if necessary 346c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 347c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return 348c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @throws UnsupportedEncodingException 349c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 350c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static byte[] encodeUCS2(String message, byte[] header) 351c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville throws UnsupportedEncodingException { 352c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] userData, textPart; 353c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville textPart = message.getBytes("utf-16be"); 354c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 355c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (header != null) { 356c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Need 1 byte for UDHL 357c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = new byte[header.length + textPart.length + 1]; 358c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 359c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData[0] = (byte)header.length; 360c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(header, 0, userData, 1, header.length); 361c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length); 362c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 363c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville else { 364c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = textPart; 365c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 366c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] ret = new byte[userData.length+1]; 367c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret[0] = (byte) (userData.length & 0xff ); 368c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(userData, 0, ret, 1, userData.length); 369c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 370c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 371c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 372c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 373c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get an SMS-SUBMIT PDU for a destination address and a message 374c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 375c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. Null means use default. 376c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 377c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message. 378c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns null on encode error. 379c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 380c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SubmitPdu getSubmitPdu(String scAddress, 381c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String destinationAddress, String message, 382c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested) { 383c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 384c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); 385c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 386c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 387c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 388c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get an SMS-SUBMIT PDU for a data message to a destination address & port 389c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 390c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. null == use default 391c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param destinationAddress the address of the destination for the message 392c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param destinationPort the port to deliver the message to at the 393c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * destination 394c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param data the data for the message 395c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a <code>SubmitPdu</code> containing the encoded SC 396c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message. 397c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns null on encode error. 398c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 399c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static SubmitPdu getSubmitPdu(String scAddress, 400c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String destinationAddress, int destinationPort, byte[] data, 401c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested) { 402c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 403c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs(); 404c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville portAddrs.destPort = destinationPort; 405c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville portAddrs.origPort = 0; 406c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville portAddrs.areEightBits = false; 407c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 408c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader smsHeader = new SmsHeader(); 409c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville smsHeader.portAddrs = portAddrs; 410c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 411c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] smsHeaderData = SmsHeader.toByteArray(smsHeader); 412c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 413c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((data.length + smsHeaderData.length + 1) > MAX_USER_DATA_BYTES) { 414c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "SMS data message may only contain " 415c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + (MAX_USER_DATA_BYTES - smsHeaderData.length - 1) + " bytes"); 416c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 417c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 418c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 419c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SubmitPdu ret = new SubmitPdu(); 420c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ByteArrayOutputStream bo = getSubmitPduHead( 421c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, 422c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-UDHI = true 423c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville statusReportRequested, ret); 424c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 425c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 426c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // No class, 8 bit data 427c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0x04); 428c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 429c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (no TP-Validity-Period) 430c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 431c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Total size 432c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(data.length + smsHeaderData.length + 1); 433c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 434c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // User data header 435c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(smsHeaderData.length); 436c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(smsHeaderData, 0, smsHeaderData.length); 437c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 438c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // User data 439c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(data, 0, data.length); 440c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 441c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret.encodedMessage = bo.toByteArray(); 442c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 443c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 444c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 445c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 446c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Create the beginning of a SUBMIT PDU. This is the part of the 447c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, 448c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * one of which takes a byte array and the other of which takes a 449c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * <code>String</code>. 450c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 451c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param scAddress Service Centre address. null == use default 452c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param destinationAddress the address of the destination for the message 453c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param mtiByte 454c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param ret <code>SubmitPdu</code> containing the encoded SC 455c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * address, if applicable, and the encoded message 456c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 457c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static ByteArrayOutputStream getSubmitPduHead( 458c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String scAddress, String destinationAddress, byte mtiByte, 459c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean statusReportRequested, SubmitPdu ret) { 460c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ByteArrayOutputStream bo = new ByteArrayOutputStream( 461c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville MAX_USER_DATA_BYTES + 40); 462c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 463c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // SMSC address with length octet, or 0 464c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (scAddress == null) { 465c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret.encodedScAddress = null; 466c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 467c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( 468c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddress); 469c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 470c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 471c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Message-Type-Indicator (and friends) 472c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (statusReportRequested) { 473c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Set TP-Status-Report-Request bit. 474c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mtiByte |= 0x20; 475c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) Log.d(LOG_TAG, "SMS status report requested"); 476c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 477c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(mtiByte); 478c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 479c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // space for TP-Message-Reference 480c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0); 481c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 482c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] daBytes; 483c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 484c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); 485c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 486c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // destination address length in BCD digits, ignoring TON byte and pad 487c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TODO Should be better. 488c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write((daBytes.length - 1) * 2 489c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); 490c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 491c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // destination address 492c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(daBytes, 0, daBytes.length); 493c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 494c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Protocol-Identifier 495c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bo.write(0); 496c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return bo; 497c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 498c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 499c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static class PduParser { 500c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte pdu[]; 501c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int cur; 502c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader userDataHeader; 503c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] userData; 504c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int mUserDataSeptetPadding; 505c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int mUserDataSize; 506c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 507c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville PduParser(byte[] pdu) { 508c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville this.pdu = pdu; 509c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville cur = 0; 510c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mUserDataSeptetPadding = 0; 511c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 512c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 513c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 514c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Parse and return the SC address prepended to SMS messages coming via 515c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * the TS 27.005 / AT interface. Returns null on invalid address 516c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 517c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getSCAddress() { 518c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int len; 519c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String ret; 520c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 521c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // length of SC Address 522c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville len = getByte(); 523c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 524c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (len == 0) { 525c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // no SC address 526c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = null; 527c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 528c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // SC address 529c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 530c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = PhoneNumberUtils 531c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville .calledPartyBCDToString(pdu, cur, len); 532c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException tr) { 533c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(LOG_TAG, "invalid SC address: ", tr); 534c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = null; 535c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 536c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 537c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 538c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville cur += len; 539c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 540c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 541c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 542c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 543c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 544c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * returns non-sign-extended byte value 545c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 546c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int getByte() { 547c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return pdu[cur++] & 0xff; 548c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 549c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 550c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 551c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Any address except the SC address (eg, originating address) See TS 552c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 23.040 9.1.2.5 553c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 554c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville GsmSmsAddress getAddress() { 555c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville GsmSmsAddress ret; 556c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 557c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // "The Address-Length field is an integer representation of 558c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // the number field, i.e. excludes any semi-octet containing only 559c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // fill bits." 560c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // The TOA field is not included as part of this 561c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int addressLength = pdu[cur] & 0xff; 562c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int lengthBytes = 2 + (addressLength + 1) / 2; 563c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 5645ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar try { 5655ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar ret = new GsmSmsAddress(pdu, cur, lengthBytes); 5665ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar } catch (ParseException e) { 5675ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar Log.e(LOG_TAG, e.getMessage()); 5685ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar ret = null; 5695ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar } 570c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 571c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville cur += lengthBytes; 572c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 573c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 574c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 575c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 576c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 577c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Parses an SC timestamp and returns a currentTimeMillis()-style 578c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * timestamp 579c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 580c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 581c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville long getSCTimestampMillis() { 582c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Service-Centre-Time-Stamp 583c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int year = IccUtils.gsmBcdByteToInt(pdu[cur++]); 584c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int month = IccUtils.gsmBcdByteToInt(pdu[cur++]); 585c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int day = IccUtils.gsmBcdByteToInt(pdu[cur++]); 586c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int hour = IccUtils.gsmBcdByteToInt(pdu[cur++]); 587c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int minute = IccUtils.gsmBcdByteToInt(pdu[cur++]); 588c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int second = IccUtils.gsmBcdByteToInt(pdu[cur++]); 589c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 590c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // For the timezone, the most significant bit of the 591c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // least significant nibble is the sign byte 592c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (meaning the max range of this field is 79 quarter-hours, 593c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // which is more than enough) 594c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 595c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte tzByte = pdu[cur++]; 596c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 597c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Mask out sign bit. 598c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08))); 599c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 600c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset; 601c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 602c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Time time = new Time(Time.TIMEZONE_UTC); 603c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 604c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // It's 2006. Should I really support years < 2000? 605c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.year = year >= 90 ? year + 1900 : year + 2000; 606c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.month = month - 1; 607c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.monthDay = day; 608c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.hour = hour; 609c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.minute = minute; 610c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville time.second = second; 611c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 612c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Timezone offset is in quarter hours. 613c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); 614c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 615c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 616c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 617c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Pulls the user data out of the PDU, and separates the payload from 618c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * the header if there is one. 619c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 620c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param hasUserDataHeader true if there is a user data header 621c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param dataInSeptets true if the data payload is in septets instead 622c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * of octets 623c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return the number of septets or octets in the user data payload 624c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 625c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) { 626c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int offset = cur; 627c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int userDataLength = pdu[offset++] & 0xff; 628c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int headerSeptets = 0; 629c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int userDataHeaderLength = 0; 630c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 631c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (hasUserDataHeader) { 632c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userDataHeaderLength = pdu[offset++] & 0xff; 633c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 634c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] udh = new byte[userDataHeaderLength]; 635c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength); 636c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userDataHeader = SmsHeader.fromByteArray(udh); 637c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville offset += userDataHeaderLength; 638c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 639c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int headerBits = (userDataHeaderLength + 1) * 8; 640c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville headerSeptets = headerBits / 7; 641c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville headerSeptets += (headerBits % 7) > 0 ? 1 : 0; 642c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mUserDataSeptetPadding = (headerSeptets * 7) - headerBits; 643c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 644c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 645c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int bufferLen; 646c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (dataInSeptets) { 647c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /* 648c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Here we just create the user data length to be the remainder of 649c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * the pdu minus the user data header, since userDataLength means 650c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * the number of uncompressed septets. 651c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 652c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bufferLen = pdu.length - offset; 653c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 654c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /* 655c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * userDataLength is the count of octets, so just subtract the 656c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * user data header. 657c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 658c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0); 659c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (bufferLen < 0) { 660c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville bufferLen = 0; 661c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 662c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 663c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 664c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userData = new byte[bufferLen]; 665c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville System.arraycopy(pdu, offset, userData, 0, userData.length); 666c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville cur = offset; 667c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 668c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (dataInSeptets) { 669c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Return the number of septets 670c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int count = userDataLength - headerSeptets; 671c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // If count < 0, return 0 (means UDL was probably incorrect) 672c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return count < 0 ? 0 : count; 673c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 674c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Return the number of octets 675c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return userData.length; 676c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 677c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 678c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 679c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 680c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns the user data payload, not including the headers 681c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 682c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return the user data payload, not including the headers 683c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 684c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] getUserData() { 685c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return userData; 686c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 687c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 688c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 689c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns the number of padding bits at the beginning of the user data 690c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * array before the start of the septets. 691c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 692c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return the number of padding bits at the beginning of the user data 693c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * array before the start of the septets 694c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 695c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int getUserDataSeptetPadding() { 696c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return mUserDataSeptetPadding; 697c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 698c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 699c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 700c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns an object representing the user data headers 701c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 702c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@hide} 703c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 704c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsHeader getUserDataHeader() { 705c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return userDataHeader; 706c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 707c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 708c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 709c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Interprets the user data payload as packed GSM 7bit characters, and 710c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * decodes them into a String. 711c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 712c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param septetCount the number of septets in the user data payload 713c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a String with the decoded characters 714c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 715c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getUserDataGSM7Bit(int septetCount, int languageTable, 716c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int languageShiftTable) { 717c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String ret; 718c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 719c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount, 720c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mUserDataSeptetPadding, languageTable, languageShiftTable); 721c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 722c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville cur += (septetCount * 7) / 8; 723c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 724c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 725c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 726c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 727c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 728c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Interprets the user data payload as UCS2 characters, and 729c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * decodes them into a String. 730c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 731c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param byteCount the number of bytes in the user data payload 732c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a String with the decoded characters 733c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 734c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getUserDataUCS2(int byteCount) { 735c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String ret; 736c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 737c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 738c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = new String(pdu, cur, byteCount, "utf-16"); 739c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (UnsupportedEncodingException ex) { 740c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = ""; 741c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); 742c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 743c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 744c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville cur += byteCount; 745c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 746c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 747c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 748c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 749c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Interprets the user data payload as KSC-5601 characters, and 750c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * decodes them into a String. 751c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 752c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param byteCount the number of bytes in the user data payload 753c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return a String with the decoded characters 754c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 755c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getUserDataKSC5601(int byteCount) { 756c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String ret; 757c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 758c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 759c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = new String(pdu, cur, byteCount, "KSC5601"); 760c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (UnsupportedEncodingException ex) { 761c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ret = ""; 762c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); 763c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 764c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 765c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville cur += byteCount; 766c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ret; 767c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 768c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 769c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean moreDataPresent() { 770c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return (pdu.length > cur); 771c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 772c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 773c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 774c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 775c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Calculate the number of septets needed to encode the message. 776c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 777c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param msgBody the message to encode 778c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param use7bitOnly ignore (but still count) illegal characters if true 779c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return TextEncodingDetails 780c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 781c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static TextEncodingDetails calculateLength(CharSequence msgBody, 782c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean use7bitOnly) { 783c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(msgBody, use7bitOnly); 784c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (ted == null) { 785c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted = new TextEncodingDetails(); 786c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int octets = msgBody.length() * 2; 787c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.codeUnitCount = msgBody.length(); 788c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (octets > MAX_USER_DATA_BYTES) { 789c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) / 790c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville MAX_USER_DATA_BYTES_WITH_HEADER; 791c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.codeUnitsRemaining = ((ted.msgCount * 792c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2; 793c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 794c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.msgCount = 1; 795c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2; 796c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 797c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ted.codeUnitSize = ENCODING_16BIT; 798c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 799c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ted; 800c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 801c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 802c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 803c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 804c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public int getProtocolIdentifier() { 805c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return protocolIdentifier; 806c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 807c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 808c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 809c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns the TP-Data-Coding-Scheme byte, for acknowledgement of SMS-PP download messages. 810c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return the TP-DCS field of the SMS header 811c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 812c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int getDataCodingScheme() { 813c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return dataCodingScheme; 814c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 815c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 816c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 817c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 818c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isReplace() { 819c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return (protocolIdentifier & 0xc0) == 0x40 820c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville && (protocolIdentifier & 0x3f) > 0 821c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville && (protocolIdentifier & 0x3f) < 8; 822c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 823c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 824c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 825c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 826c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isCphsMwiMessage() { 827c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear() 828c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville || ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); 829c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 830c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 831c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 832c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 833c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isMWIClearMessage() { 834c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (isMwi && !mwiSense) { 835c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 836c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 837c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 838c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return originatingAddress != null 839c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear(); 840c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 841c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 842c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 843c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 844c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isMWISetMessage() { 845c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (isMwi && mwiSense) { 846c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 847c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 848c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 849c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return originatingAddress != null 850c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); 851c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 852c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 853c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 854c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 855c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isMwiDontStore() { 856c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (isMwi && mwiDontStore) { 857c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 858c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 859c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 860c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (isCphsMwiMessage()) { 861c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // See CPHS 4.2 Section B.4.2.1 862c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // If the user data is a single space char, do not store 863c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // the message. Otherwise, store and display as usual 864c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (" ".equals(getMessageBody())) { 865c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville ; 866c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 867c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 868c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 869c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 870c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return false; 871c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 872c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 873c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 874c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 875c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public int getStatus() { 876c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return status; 877c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 878c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 879c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 880c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 881c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isStatusReportMessage() { 882c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return isStatusReportMessage; 883c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 884c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 885c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 886c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 887c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isReplyPathPresent() { 888c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return replyPathPresent; 889c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 890c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 891c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 892c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6] 893c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: 894c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * ME/TA converts each octet of TP data unit into two IRA character long 895c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * hex number (e.g. octet with integer value 42 is presented to TE as two 896c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, 897c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * something else... 898c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 899c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void parsePdu(byte[] pdu) { 900c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mPdu = pdu; 901c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Log.d(LOG_TAG, "raw sms message:"); 902c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Log.d(LOG_TAG, s); 903c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 904c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville PduParser p = new PduParser(pdu); 905c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 906c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddress = p.getSCAddress(); 907c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 908c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (scAddress != null) { 909c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) Log.d(LOG_TAG, "SMS SC address: " + scAddress); 910c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 911c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 912c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TODO(mkf) support reply path, user data header indicator 913c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 914c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Message-Type-Indicator 915c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 9.2.3 916c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int firstByte = p.getByte(); 917c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 918c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mti = firstByte & 0x3; 919c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch (mti) { 920c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Message-Type-Indicator 921c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 9.2.3 922c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 0: 923c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 3: //GSM 03.40 9.2.3.1: MTI == 3 is Reserved. 924c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville //This should be processed in the same way as MTI == 0 (Deliver) 925c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville parseSmsDeliver(p, firstByte); 926c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 927c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 2: 928c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville parseSmsStatusReport(p, firstByte); 929c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 930c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville default: 931c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TODO(mkf) the rest of these 932c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville throw new RuntimeException("Unsupported message type"); 933c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 934c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 935c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 936c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 937c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Parses a SMS-STATUS-REPORT message. 938c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 939c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param p A PduParser, cued past the first byte. 940c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param firstByte The first byte of the PDU, which contains MTI, etc. 941c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 942c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void parseSmsStatusReport(PduParser p, int firstByte) { 943c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville isStatusReportMessage = true; 944c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 945c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Status-Report-Qualifier bit == 0 for SUBMIT 946c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville forSubmit = (firstByte & 0x20) == 0x00; 947c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Message-Reference 948c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageRef = p.getByte(); 949c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Recipient-Address 950c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville recipientAddress = p.getAddress(); 951c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Service-Centre-Time-Stamp 952c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scTimeMillis = p.getSCTimestampMillis(); 953c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Discharge-Time 954c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville dischargeTimeMillis = p.getSCTimestampMillis(); 955c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Status 956c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville status = p.getByte(); 957c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 958c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // The following are optional fields that may or may not be present. 959c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (p.moreDataPresent()) { 960c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Parameter-Indicator 961c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int extraParams = p.getByte(); 962c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int moreExtraParams = extraParams; 963c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville while ((moreExtraParams & 0x80) != 0) { 964c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // We only know how to parse a few extra parameters, all 965c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // indicated in the first TP-PI octet, so skip over any 966c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // additional TP-PI octets. 967c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville moreExtraParams = p.getByte(); 968c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 96956c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // As per 3GPP 23.040 section 9.2.3.27 TP-Parameter-Indicator, 97056c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // only process the byte if the reserved bits (bits3 to 6) are zero. 97156c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan if ((extraParams & 0x78) == 0) { 97256c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // TP-Protocol-Identifier 97356c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan if ((extraParams & 0x01) != 0) { 97456c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan protocolIdentifier = p.getByte(); 97556c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan } 97656c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // TP-Data-Coding-Scheme 97756c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan if ((extraParams & 0x02) != 0) { 97856c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan dataCodingScheme = p.getByte(); 97956c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan } 98056c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan // TP-User-Data-Length (implies existence of TP-User-Data) 98156c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan if ((extraParams & 0x04) != 0) { 98256c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; 98356c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan parseUserData(p, hasUserDataHeader); 98456c949ded0e352444806dd04bbca1895a2c75a9bHuanze Lan } 985c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 986c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 987c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 988c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 989c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void parseSmsDeliver(PduParser p, int firstByte) { 990c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville replyPathPresent = (firstByte & 0x80) == 0x80; 991c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 992c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville originatingAddress = p.getAddress(); 993c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 994c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (originatingAddress != null) { 995c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) Log.v(LOG_TAG, "SMS originating address: " 996c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + originatingAddress.address); 997c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 998c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 999c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Protocol-Identifier (TP-PID) 1000c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TS 23.040 9.2.3.9 1001c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protocolIdentifier = p.getByte(); 1002c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1003c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // TP-Data-Coding-Scheme 1004c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // see TS 23.038 1005c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville dataCodingScheme = p.getByte(); 1006c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1007c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) { 1008c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.v(LOG_TAG, "SMS TP-PID:" + protocolIdentifier 1009c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + " data coding scheme: " + dataCodingScheme); 1010c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1011c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1012c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scTimeMillis = p.getSCTimestampMillis(); 1013c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1014c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); 1015c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1016c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; 1017c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1018c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville parseUserData(p, hasUserDataHeader); 1019c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1020c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1021c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 1022c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Parses the User Data of an SMS. 1023c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 1024c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param p The current PduParser. 1025c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param hasUserDataHeader Indicates whether a header is present in the 1026c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * User Data. 1027c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 1028c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void parseUserData(PduParser p, boolean hasUserDataHeader) { 1029c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean hasMessageClass = false; 1030c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean userDataCompressed = false; 1031c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1032c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int encodingType = ENCODING_UNKNOWN; 1033c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1034c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Look up the data encoding scheme 1035c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((dataCodingScheme & 0x80) == 0) { 1036c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Bits 7..4 == 0xxx 1037c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville automaticDeletion = (0 != (dataCodingScheme & 0x40)); 1038c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userDataCompressed = (0 != (dataCodingScheme & 0x20)); 1039c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville hasMessageClass = (0 != (dataCodingScheme & 0x10)); 1040c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1041c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (userDataCompressed) { 1042c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.w(LOG_TAG, "4 - Unsupported SMS data coding scheme " 1043c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + "(compression) " + (dataCodingScheme & 0xff)); 1044c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1045c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch ((dataCodingScheme >> 2) & 0x3) { 1046c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 0: // GSM 7 bit default alphabet 1047c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_7BIT; 1048c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1049c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1050c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 2: // UCS 2 (16bit) 1051c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_16BIT; 1052c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1053c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1054c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 1: // 8 bit data 1055c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 3: // reserved 1056c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " 1057c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + (dataCodingScheme & 0xff)); 1058c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_8BIT; 1059c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1060c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1061c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1062c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else if ((dataCodingScheme & 0xf0) == 0xf0) { 1063c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville automaticDeletion = false; 1064c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville hasMessageClass = true; 1065c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userDataCompressed = false; 1066c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1067c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (0 == (dataCodingScheme & 0x04)) { 1068c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // GSM 7 bit default alphabet 1069c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_7BIT; 1070c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1071c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 8 bit data 1072c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_8BIT; 1073c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1074c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else if ((dataCodingScheme & 0xF0) == 0xC0 1075c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville || (dataCodingScheme & 0xF0) == 0xD0 1076c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville || (dataCodingScheme & 0xF0) == 0xE0) { 1077c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 1078c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1079c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 0xC0 == 7 bit, don't store 1080c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 0xD0 == 7 bit, store 1081c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 0xE0 == UCS-2, store 1082c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1083c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((dataCodingScheme & 0xF0) == 0xE0) { 1084c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_16BIT; 1085c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1086c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_7BIT; 1087c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1088c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1089c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville userDataCompressed = false; 1090c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean active = ((dataCodingScheme & 0x08) == 0x08); 1091c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1092c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // bit 0x04 reserved 1093c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1094c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if ((dataCodingScheme & 0x03) == 0x00) { 1095c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville isMwi = true; 1096c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mwiSense = active; 1097c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0); 1098c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1099c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville isMwi = false; 1100c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1101c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.w(LOG_TAG, "MWI for fax, email, or other " 1102c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + (dataCodingScheme & 0xff)); 1103c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1104c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else if ((dataCodingScheme & 0xC0) == 0x80) { 1105c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 1106c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // 0x80..0xBF == Reserved coding groups 1107c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (dataCodingScheme == 0x84) { 1108c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // This value used for KSC5601 by carriers in Korea. 1109c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType = ENCODING_KSC5601; 1110c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1111c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.w(LOG_TAG, "5 - Unsupported SMS data coding scheme " 1112c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + (dataCodingScheme & 0xff)); 1113c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1114c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1115c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " 1116c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + (dataCodingScheme & 0xff)); 1117c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1118c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1119c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // set both the user data and the user data header. 1120c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int count = p.constructUserData(hasUserDataHeader, 1121c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encodingType == ENCODING_7BIT); 1122c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville this.userData = p.getUserData(); 1123c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville this.userDataHeader = p.getUserDataHeader(); 1124c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1125c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch (encodingType) { 1126c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_UNKNOWN: 1127c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_8BIT: 1128c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageBody = null; 1129c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1130c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1131c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_7BIT: 1132c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageBody = p.getUserDataGSM7Bit(count, 1133c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville hasUserDataHeader ? userDataHeader.languageTable : 0, 1134c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville hasUserDataHeader ? userDataHeader.languageShiftTable : 0); 1135c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1136c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1137c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_16BIT: 1138c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageBody = p.getUserDataUCS2(count); 1139c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1140c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1141c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case ENCODING_KSC5601: 1142c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageBody = p.getUserDataKSC5601(count); 1143c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1144c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1145c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1146c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); 1147c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1148c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (messageBody != null) { 1149c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville parseMessageBody(); 1150c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1151c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1152c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (!hasMessageClass) { 1153c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.UNKNOWN; 1154c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 1155c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch (dataCodingScheme & 0x3) { 1156c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 0: 1157c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.CLASS_0; 1158c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1159c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 1: 1160c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.CLASS_1; 1161c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1162c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 2: 1163c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.CLASS_2; 1164c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1165c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case 3: 1166c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville messageClass = MessageClass.CLASS_3; 1167c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 1168c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1169c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1170c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1171c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1172c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 1173c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@inheritDoc} 1174c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 1175c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 1176c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public MessageClass getMessageClass() { 1177c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return messageClass; 1178c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1179c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 1180c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 1181c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns true if this is a (U)SIM data download type SM. 1182c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * See 3GPP TS 31.111 section 9.1 and TS 23.040 section 9.2.3.9. 1183c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 1184c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return true if this is a USIM data download message; false otherwise 1185c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 1186c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean isUsimDataDownload() { 1187c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return messageClass == MessageClass.CLASS_2 && 1188c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville (protocolIdentifier == 0x7f || protocolIdentifier == 0x7c); 1189c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 1190c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville} 1191