SmsMessage.java revision 767a662ecde33c3979bf02b793d392aca0403162
1767a662ecde33c3979bf02b793d392aca0403162Wink Saville/*
2767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Copyright (C) 2006 The Android Open Source Project
3767a662ecde33c3979bf02b793d392aca0403162Wink Saville *
4767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
5767a662ecde33c3979bf02b793d392aca0403162Wink Saville * you may not use this file except in compliance with the License.
6767a662ecde33c3979bf02b793d392aca0403162Wink Saville * You may obtain a copy of the License at
7767a662ecde33c3979bf02b793d392aca0403162Wink Saville *
8767a662ecde33c3979bf02b793d392aca0403162Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
9767a662ecde33c3979bf02b793d392aca0403162Wink Saville *
10767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Unless required by applicable law or agreed to in writing, software
11767a662ecde33c3979bf02b793d392aca0403162Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
12767a662ecde33c3979bf02b793d392aca0403162Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13767a662ecde33c3979bf02b793d392aca0403162Wink Saville * See the License for the specific language governing permissions and
14767a662ecde33c3979bf02b793d392aca0403162Wink Saville * limitations under the License.
15767a662ecde33c3979bf02b793d392aca0403162Wink Saville */
16767a662ecde33c3979bf02b793d392aca0403162Wink Saville
17767a662ecde33c3979bf02b793d392aca0403162Wink Savillepackage com.android.internal.telephony.gsm;
18767a662ecde33c3979bf02b793d392aca0403162Wink Saville
19767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.os.Parcel;
20767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.telephony.PhoneNumberUtils;
21767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.text.format.Time;
22767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.util.Config;
23767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.util.Log;
24767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.IccUtils;
25767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.EncodeException;
26767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.GsmAlphabet;
27767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SmsHeader;
28767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SmsMessageBase;
29767a662ecde33c3979bf02b793d392aca0403162Wink Saville
30767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport java.io.ByteArrayOutputStream;
31767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport java.io.UnsupportedEncodingException;
32767a662ecde33c3979bf02b793d392aca0403162Wink Saville
33767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.ENCODING_7BIT;
34767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.ENCODING_8BIT;
35767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.ENCODING_16BIT;
36767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.ENCODING_UNKNOWN;
37767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
38767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
39767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
40767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
41767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.SmsMessage.MessageClass;
42767a662ecde33c3979bf02b793d392aca0403162Wink Saville
43767a662ecde33c3979bf02b793d392aca0403162Wink Saville/**
44767a662ecde33c3979bf02b793d392aca0403162Wink Saville * A Short Message Service message.
45767a662ecde33c3979bf02b793d392aca0403162Wink Saville *
46767a662ecde33c3979bf02b793d392aca0403162Wink Saville */
47767a662ecde33c3979bf02b793d392aca0403162Wink Savillepublic class SmsMessage extends SmsMessageBase{
48767a662ecde33c3979bf02b793d392aca0403162Wink Saville    static final String LOG_TAG = "GSM";
49767a662ecde33c3979bf02b793d392aca0403162Wink Saville
50767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private MessageClass messageClass;
51767a662ecde33c3979bf02b793d392aca0403162Wink Saville
52767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
53767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * TP-Message-Type-Indicator
54767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * 9.2.3
55767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
56767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private int mti;
57767a662ecde33c3979bf02b793d392aca0403162Wink Saville
58767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** TP-Protocol-Identifier (TP-PID) */
59767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private int protocolIdentifier;
60767a662ecde33c3979bf02b793d392aca0403162Wink Saville
61767a662ecde33c3979bf02b793d392aca0403162Wink Saville    // TP-Data-Coding-Scheme
62767a662ecde33c3979bf02b793d392aca0403162Wink Saville    // see TS 23.038
63767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private int dataCodingScheme;
64767a662ecde33c3979bf02b793d392aca0403162Wink Saville
65767a662ecde33c3979bf02b793d392aca0403162Wink Saville    // TP-Reply-Path
66767a662ecde33c3979bf02b793d392aca0403162Wink Saville    // e.g. 23.040 9.2.2.1
67767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private boolean replyPathPresent = false;
68767a662ecde33c3979bf02b793d392aca0403162Wink Saville
69767a662ecde33c3979bf02b793d392aca0403162Wink Saville    // "Message Marked for Automatic Deletion Group"
70767a662ecde33c3979bf02b793d392aca0403162Wink Saville    // 23.038 Section 4
71767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private boolean automaticDeletion;
72767a662ecde33c3979bf02b793d392aca0403162Wink Saville
73767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** True if Status Report is for SMS-SUBMIT; false for SMS-COMMAND. */
74767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private boolean forSubmit;
75767a662ecde33c3979bf02b793d392aca0403162Wink Saville
76767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** The address of the receiver. */
77767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private GsmSmsAddress recipientAddress;
78767a662ecde33c3979bf02b793d392aca0403162Wink Saville
79767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** Time when SMS-SUBMIT was delivered from SC to MSE. */
80767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private long dischargeTimeMillis;
81767a662ecde33c3979bf02b793d392aca0403162Wink Saville
82767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
83767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *  TP-Status - status of a previously submitted SMS.
84767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *  This field applies to SMS-STATUS-REPORT messages.  0 indicates success;
85767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *  see TS 23.040, 9.2.3.15 for description of other possible values.
86767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
87767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private int status;
88767a662ecde33c3979bf02b793d392aca0403162Wink Saville
89767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
90767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *  TP-Status - status of a previously submitted SMS.
91767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *  This field is true iff the message is a SMS-STATUS-REPORT message.
92767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
93767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private boolean isStatusReportMessage = false;
94767a662ecde33c3979bf02b793d392aca0403162Wink Saville
95767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static class SubmitPdu extends SubmitPduBase {
96767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
97767a662ecde33c3979bf02b793d392aca0403162Wink Saville
98767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
99767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Create an SmsMessage from a raw PDU.
100767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
101767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessage createFromPdu(byte[] pdu) {
102767a662ecde33c3979bf02b793d392aca0403162Wink Saville        try {
103767a662ecde33c3979bf02b793d392aca0403162Wink Saville            SmsMessage msg = new SmsMessage();
104767a662ecde33c3979bf02b793d392aca0403162Wink Saville            msg.parsePdu(pdu);
105767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return msg;
106767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } catch (RuntimeException ex) {
107767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
108767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return null;
109767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
110767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
111767a662ecde33c3979bf02b793d392aca0403162Wink Saville
112767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
113767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
114767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * +CMT unsolicited response (PDU mode, of course)
115767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *  +CMT: [&lt;alpha>],<length><CR><LF><pdu>
116767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
117767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Only public for debugging
118767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
119767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * {@hide}
120767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
121767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessage newFromCMT(String[] lines) {
122767a662ecde33c3979bf02b793d392aca0403162Wink Saville        try {
123767a662ecde33c3979bf02b793d392aca0403162Wink Saville            SmsMessage msg = new SmsMessage();
124767a662ecde33c3979bf02b793d392aca0403162Wink Saville            msg.parsePdu(IccUtils.hexStringToBytes(lines[1]));
125767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return msg;
126767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } catch (RuntimeException ex) {
127767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
128767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return null;
129767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
130767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
131767a662ecde33c3979bf02b793d392aca0403162Wink Saville
132767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** @hide */
133767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessage newFromCMTI(String line) {
134767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // the thinking here is not to read the message immediately
135767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // FTA test case
136767a662ecde33c3979bf02b793d392aca0403162Wink Saville        Log.e(LOG_TAG, "newFromCMTI: not yet supported");
137767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return null;
138767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
139767a662ecde33c3979bf02b793d392aca0403162Wink Saville
140767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** @hide */
141767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessage newFromCDS(String line) {
142767a662ecde33c3979bf02b793d392aca0403162Wink Saville        try {
143767a662ecde33c3979bf02b793d392aca0403162Wink Saville            SmsMessage msg = new SmsMessage();
144767a662ecde33c3979bf02b793d392aca0403162Wink Saville            msg.parsePdu(IccUtils.hexStringToBytes(line));
145767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return msg;
146767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } catch (RuntimeException ex) {
147767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex);
148767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return null;
149767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
150767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
151767a662ecde33c3979bf02b793d392aca0403162Wink Saville
152767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
153767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Note: This functionality is currently not supported in GSM mode.
154767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @hide
155767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
156767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessageBase newFromParcel(Parcel p){
157767a662ecde33c3979bf02b793d392aca0403162Wink Saville        Log.w(LOG_TAG, "newFromParcel: is not supported in GSM mode.");
158767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return null;
159767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
160767a662ecde33c3979bf02b793d392aca0403162Wink Saville
161767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
162767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Create an SmsMessage from an SMS EF record.
163767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
164767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param index Index of SMS record. This should be index in ArrayList
165767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *              returned by SmsManager.getAllMessagesFromSim + 1.
166767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param data Record data.
167767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return An SmsMessage representing the record.
168767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
169767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @hide
170767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
171767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessage createFromEfRecord(int index, byte[] data) {
172767a662ecde33c3979bf02b793d392aca0403162Wink Saville        try {
173767a662ecde33c3979bf02b793d392aca0403162Wink Saville            SmsMessage msg = new SmsMessage();
174767a662ecde33c3979bf02b793d392aca0403162Wink Saville
175767a662ecde33c3979bf02b793d392aca0403162Wink Saville            msg.indexOnIcc = index;
176767a662ecde33c3979bf02b793d392aca0403162Wink Saville
177767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT,
178767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // or STORED_UNSENT
179767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // See TS 51.011 10.5.3
180767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if ((data[0] & 1) == 0) {
181767a662ecde33c3979bf02b793d392aca0403162Wink Saville                Log.w(LOG_TAG,
182767a662ecde33c3979bf02b793d392aca0403162Wink Saville                        "SMS parsing failed: Trying to parse a free record");
183767a662ecde33c3979bf02b793d392aca0403162Wink Saville                return null;
184767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
185767a662ecde33c3979bf02b793d392aca0403162Wink Saville                msg.statusOnIcc = data[0] & 0x07;
186767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
187767a662ecde33c3979bf02b793d392aca0403162Wink Saville
188767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int size = data.length - 1;
189767a662ecde33c3979bf02b793d392aca0403162Wink Saville
190767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Note: Data may include trailing FF's.  That's OK; message
191767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // should still parse correctly.
192767a662ecde33c3979bf02b793d392aca0403162Wink Saville            byte[] pdu = new byte[size];
193767a662ecde33c3979bf02b793d392aca0403162Wink Saville            System.arraycopy(data, 1, pdu, 0, size);
194767a662ecde33c3979bf02b793d392aca0403162Wink Saville            msg.parsePdu(pdu);
195767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return msg;
196767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } catch (RuntimeException ex) {
197767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
198767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return null;
199767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
200767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
201767a662ecde33c3979bf02b793d392aca0403162Wink Saville
202767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
203767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
204767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * length in bytes (not hex chars) less the SMSC header
205767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
206767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static int getTPLayerLengthForPDU(String pdu) {
207767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int len = pdu.length() / 2;
208767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int smscLen = 0;
209767a662ecde33c3979bf02b793d392aca0403162Wink Saville
210767a662ecde33c3979bf02b793d392aca0403162Wink Saville        smscLen = Integer.parseInt(pdu.substring(0, 2), 16);
211767a662ecde33c3979bf02b793d392aca0403162Wink Saville
212767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return len - smscLen - 1;
213767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
214767a662ecde33c3979bf02b793d392aca0403162Wink Saville
215767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
216767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Get an SMS-SUBMIT PDU for a destination address and a message
217767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
218767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param scAddress Service Centre address.  Null means use default.
219767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return a <code>SubmitPdu</code> containing the encoded SC
220767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         address, if applicable, and the encoded message.
221767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         Returns null on encode error.
222767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @hide
223767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
224767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SubmitPdu getSubmitPdu(String scAddress,
225767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String destinationAddress, String message,
226767a662ecde33c3979bf02b793d392aca0403162Wink Saville            boolean statusReportRequested, byte[] header) {
227767a662ecde33c3979bf02b793d392aca0403162Wink Saville
228767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Perform null parameter checks.
229767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (message == null || destinationAddress == null) {
230767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return null;
231767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
232767a662ecde33c3979bf02b793d392aca0403162Wink Saville
233767a662ecde33c3979bf02b793d392aca0403162Wink Saville        SubmitPdu ret = new SubmitPdu();
234767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // MTI = SMS-SUBMIT, UDHI = header != null
235767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00));
236767a662ecde33c3979bf02b793d392aca0403162Wink Saville        ByteArrayOutputStream bo = getSubmitPduHead(
237767a662ecde33c3979bf02b793d392aca0403162Wink Saville                scAddress, destinationAddress, mtiByte,
238767a662ecde33c3979bf02b793d392aca0403162Wink Saville                statusReportRequested, ret);
239767a662ecde33c3979bf02b793d392aca0403162Wink Saville
240767a662ecde33c3979bf02b793d392aca0403162Wink Saville        try {
241767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // First, try encoding it with the GSM alphabet
242767a662ecde33c3979bf02b793d392aca0403162Wink Saville
243767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // User Data (and length)
244767a662ecde33c3979bf02b793d392aca0403162Wink Saville            byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header);
245767a662ecde33c3979bf02b793d392aca0403162Wink Saville
246767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
247767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // Message too long
248767a662ecde33c3979bf02b793d392aca0403162Wink Saville                return null;
249767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
250767a662ecde33c3979bf02b793d392aca0403162Wink Saville
251767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TP-Data-Coding-Scheme
252767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Default encoding, uncompressed
253767a662ecde33c3979bf02b793d392aca0403162Wink Saville            bo.write(0x00);
254767a662ecde33c3979bf02b793d392aca0403162Wink Saville
255767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // (no TP-Validity-Period)
256767a662ecde33c3979bf02b793d392aca0403162Wink Saville
257767a662ecde33c3979bf02b793d392aca0403162Wink Saville            bo.write(userData, 0, userData.length);
258767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } catch (EncodeException ex) {
259767a662ecde33c3979bf02b793d392aca0403162Wink Saville            byte[] userData, textPart;
260767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Encoding to the 7-bit alphabet failed. Let's see if we can
261767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // send it as a UCS-2 encoded message
262767a662ecde33c3979bf02b793d392aca0403162Wink Saville
263767a662ecde33c3979bf02b793d392aca0403162Wink Saville            try {
264767a662ecde33c3979bf02b793d392aca0403162Wink Saville                textPart = message.getBytes("utf-16be");
265767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } catch (UnsupportedEncodingException uex) {
266767a662ecde33c3979bf02b793d392aca0403162Wink Saville                Log.e(LOG_TAG,
267767a662ecde33c3979bf02b793d392aca0403162Wink Saville                      "Implausible UnsupportedEncodingException ",
268767a662ecde33c3979bf02b793d392aca0403162Wink Saville                      uex);
269767a662ecde33c3979bf02b793d392aca0403162Wink Saville                return null;
270767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
271767a662ecde33c3979bf02b793d392aca0403162Wink Saville
272767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (header != null) {
273767a662ecde33c3979bf02b793d392aca0403162Wink Saville                userData = new byte[header.length + textPart.length];
274767a662ecde33c3979bf02b793d392aca0403162Wink Saville
275767a662ecde33c3979bf02b793d392aca0403162Wink Saville                System.arraycopy(header, 0, userData, 0, header.length);
276767a662ecde33c3979bf02b793d392aca0403162Wink Saville                System.arraycopy(textPart, 0, userData, header.length, textPart.length);
277767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
278767a662ecde33c3979bf02b793d392aca0403162Wink Saville            else {
279767a662ecde33c3979bf02b793d392aca0403162Wink Saville                userData = textPart;
280767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
281767a662ecde33c3979bf02b793d392aca0403162Wink Saville
282767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (userData.length > MAX_USER_DATA_BYTES) {
283767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // Message too long
284767a662ecde33c3979bf02b793d392aca0403162Wink Saville                return null;
285767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
286767a662ecde33c3979bf02b793d392aca0403162Wink Saville
287767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TP-Data-Coding-Scheme
288767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Class 3, UCS-2 encoding, uncompressed
289767a662ecde33c3979bf02b793d392aca0403162Wink Saville            bo.write(0x0b);
290767a662ecde33c3979bf02b793d392aca0403162Wink Saville
291767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // (no TP-Validity-Period)
292767a662ecde33c3979bf02b793d392aca0403162Wink Saville
293767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TP-UDL
294767a662ecde33c3979bf02b793d392aca0403162Wink Saville            bo.write(userData.length);
295767a662ecde33c3979bf02b793d392aca0403162Wink Saville
296767a662ecde33c3979bf02b793d392aca0403162Wink Saville            bo.write(userData, 0, userData.length);
297767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
298767a662ecde33c3979bf02b793d392aca0403162Wink Saville
299767a662ecde33c3979bf02b793d392aca0403162Wink Saville        ret.encodedMessage = bo.toByteArray();
300767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return ret;
301767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
302767a662ecde33c3979bf02b793d392aca0403162Wink Saville
303767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
304767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Get an SMS-SUBMIT PDU for a destination address and a message
305767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
306767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param scAddress Service Centre address.  Null means use default.
307767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return a <code>SubmitPdu</code> containing the encoded SC
308767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         address, if applicable, and the encoded message.
309767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         Returns null on encode error.
310767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
311767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SubmitPdu getSubmitPdu(String scAddress,
312767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String destinationAddress, String message,
313767a662ecde33c3979bf02b793d392aca0403162Wink Saville            boolean statusReportRequested) {
314767a662ecde33c3979bf02b793d392aca0403162Wink Saville
315767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null);
316767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
317767a662ecde33c3979bf02b793d392aca0403162Wink Saville
318767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
319767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
320767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
321767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param scAddress Service Centre address. null == use default
322767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param destinationAddress the address of the destination for the message
323767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param destinationPort the port to deliver the message to at the
324767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *        destination
325767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param data the dat for the message
326767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return a <code>SubmitPdu</code> containing the encoded SC
327767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         address, if applicable, and the encoded message.
328767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         Returns null on encode error.
329767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
330767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SubmitPdu getSubmitPdu(String scAddress,
331767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String destinationAddress, short destinationPort, byte[] data,
332767a662ecde33c3979bf02b793d392aca0403162Wink Saville            boolean statusReportRequested) {
333767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) {
334767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.e(LOG_TAG, "SMS data message may only contain "
335767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    + (MAX_USER_DATA_BYTES - 7) + " bytes");
336767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return null;
337767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
338767a662ecde33c3979bf02b793d392aca0403162Wink Saville
339767a662ecde33c3979bf02b793d392aca0403162Wink Saville        SubmitPdu ret = new SubmitPdu();
340767a662ecde33c3979bf02b793d392aca0403162Wink Saville        ByteArrayOutputStream bo = getSubmitPduHead(
341767a662ecde33c3979bf02b793d392aca0403162Wink Saville                scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT,
342767a662ecde33c3979bf02b793d392aca0403162Wink Saville                                                            // TP-UDHI = true
343767a662ecde33c3979bf02b793d392aca0403162Wink Saville                statusReportRequested, ret);
344767a662ecde33c3979bf02b793d392aca0403162Wink Saville
345767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Data-Coding-Scheme
346767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // No class, 8 bit data
347767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(0x04);
348767a662ecde33c3979bf02b793d392aca0403162Wink Saville
349767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // (no TP-Validity-Period)
350767a662ecde33c3979bf02b793d392aca0403162Wink Saville
351767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // User data size
352767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(data.length + 7);
353767a662ecde33c3979bf02b793d392aca0403162Wink Saville
354767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // User data header size
355767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(0x06); // header is 6 octets
356767a662ecde33c3979bf02b793d392aca0403162Wink Saville
357767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // User data header, indicating the destination port
358767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT); // port
359767a662ecde33c3979bf02b793d392aca0403162Wink Saville                                                                // addressing
360767a662ecde33c3979bf02b793d392aca0403162Wink Saville                                                                // header
361767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(0x04); // each port is 2 octets
362767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write((destinationPort >> 8) & 0xFF); // MSB of destination port
363767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(destinationPort & 0xFF); // LSB of destination port
364767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(0x00); // MSB of originating port
365767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(0x00); // LSB of originating port
366767a662ecde33c3979bf02b793d392aca0403162Wink Saville
367767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // User data
368767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(data, 0, data.length);
369767a662ecde33c3979bf02b793d392aca0403162Wink Saville
370767a662ecde33c3979bf02b793d392aca0403162Wink Saville        ret.encodedMessage = bo.toByteArray();
371767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return ret;
372767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
373767a662ecde33c3979bf02b793d392aca0403162Wink Saville
374767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
375767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Create the beginning of a SUBMIT PDU.  This is the part of the
376767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu},
377767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * one of which takes a byte array and the other of which takes a
378767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * <code>String</code>.
379767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
380767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param scAddress Service Centre address. null == use default
381767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param destinationAddress the address of the destination for the message
382767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param mtiByte
383767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param ret <code>SubmitPdu</code> containing the encoded SC
384767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *        address, if applicable, and the encoded message
385767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
386767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private static ByteArrayOutputStream getSubmitPduHead(
387767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String scAddress, String destinationAddress, byte mtiByte,
388767a662ecde33c3979bf02b793d392aca0403162Wink Saville            boolean statusReportRequested, SubmitPdu ret) {
389767a662ecde33c3979bf02b793d392aca0403162Wink Saville        ByteArrayOutputStream bo = new ByteArrayOutputStream(
390767a662ecde33c3979bf02b793d392aca0403162Wink Saville                MAX_USER_DATA_BYTES + 40);
391767a662ecde33c3979bf02b793d392aca0403162Wink Saville
392767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // SMSC address with length octet, or 0
393767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (scAddress == null) {
394767a662ecde33c3979bf02b793d392aca0403162Wink Saville            ret.encodedScAddress = null;
395767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else {
396767a662ecde33c3979bf02b793d392aca0403162Wink Saville            ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
397767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    scAddress);
398767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
399767a662ecde33c3979bf02b793d392aca0403162Wink Saville
400767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Message-Type-Indicator (and friends)
401767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (statusReportRequested) {
402767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Set TP-Status-Report-Request bit.
403767a662ecde33c3979bf02b793d392aca0403162Wink Saville            mtiByte |= 0x20;
404767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (Config.LOGD) Log.d(LOG_TAG, "SMS status report requested");
405767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
406767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(mtiByte);
407767a662ecde33c3979bf02b793d392aca0403162Wink Saville
408767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // space for TP-Message-Reference
409767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(0);
410767a662ecde33c3979bf02b793d392aca0403162Wink Saville
411767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte[] daBytes;
412767a662ecde33c3979bf02b793d392aca0403162Wink Saville
413767a662ecde33c3979bf02b793d392aca0403162Wink Saville        daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress);
414767a662ecde33c3979bf02b793d392aca0403162Wink Saville
415767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // destination address length in BCD digits, ignoring TON byte and pad
416767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TODO Should be better.
417767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write((daBytes.length - 1) * 2
418767a662ecde33c3979bf02b793d392aca0403162Wink Saville                - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0));
419767a662ecde33c3979bf02b793d392aca0403162Wink Saville
420767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // destination address
421767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(daBytes, 0, daBytes.length);
422767a662ecde33c3979bf02b793d392aca0403162Wink Saville
423767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Protocol-Identifier
424767a662ecde33c3979bf02b793d392aca0403162Wink Saville        bo.write(0);
425767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return bo;
426767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
427767a662ecde33c3979bf02b793d392aca0403162Wink Saville
428767a662ecde33c3979bf02b793d392aca0403162Wink Saville    static class PduParser {
429767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte pdu[];
430767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int cur;
431767a662ecde33c3979bf02b793d392aca0403162Wink Saville        SmsHeader userDataHeader;
432767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte[] userData;
433767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int mUserDataSeptetPadding;
434767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int mUserDataSize;
435767a662ecde33c3979bf02b793d392aca0403162Wink Saville
436767a662ecde33c3979bf02b793d392aca0403162Wink Saville        PduParser(String s) {
437767a662ecde33c3979bf02b793d392aca0403162Wink Saville            this(IccUtils.hexStringToBytes(s));
438767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
439767a662ecde33c3979bf02b793d392aca0403162Wink Saville
440767a662ecde33c3979bf02b793d392aca0403162Wink Saville        PduParser(byte[] pdu) {
441767a662ecde33c3979bf02b793d392aca0403162Wink Saville            this.pdu = pdu;
442767a662ecde33c3979bf02b793d392aca0403162Wink Saville            cur = 0;
443767a662ecde33c3979bf02b793d392aca0403162Wink Saville            mUserDataSeptetPadding = 0;
444767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
445767a662ecde33c3979bf02b793d392aca0403162Wink Saville
446767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
447767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Parse and return the SC address prepended to SMS messages coming via
448767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * the TS 27.005 / AT interface.  Returns null on invalid address
449767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
450767a662ecde33c3979bf02b793d392aca0403162Wink Saville        String getSCAddress() {
451767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int len;
452767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String ret;
453767a662ecde33c3979bf02b793d392aca0403162Wink Saville
454767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // length of SC Address
455767a662ecde33c3979bf02b793d392aca0403162Wink Saville            len = getByte();
456767a662ecde33c3979bf02b793d392aca0403162Wink Saville
457767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (len == 0) {
458767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // no SC address
459767a662ecde33c3979bf02b793d392aca0403162Wink Saville                ret = null;
460767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
461767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // SC address
462767a662ecde33c3979bf02b793d392aca0403162Wink Saville                try {
463767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    ret = PhoneNumberUtils
464767a662ecde33c3979bf02b793d392aca0403162Wink Saville                            .calledPartyBCDToString(pdu, cur, len);
465767a662ecde33c3979bf02b793d392aca0403162Wink Saville                } catch (RuntimeException tr) {
466767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    Log.d(LOG_TAG, "invalid SC address: ", tr);
467767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    ret = null;
468767a662ecde33c3979bf02b793d392aca0403162Wink Saville                }
469767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
470767a662ecde33c3979bf02b793d392aca0403162Wink Saville
471767a662ecde33c3979bf02b793d392aca0403162Wink Saville            cur += len;
472767a662ecde33c3979bf02b793d392aca0403162Wink Saville
473767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return ret;
474767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
475767a662ecde33c3979bf02b793d392aca0403162Wink Saville
476767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
477767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * returns non-sign-extended byte value
478767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
479767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int getByte() {
480767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return pdu[cur++] & 0xff;
481767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
482767a662ecde33c3979bf02b793d392aca0403162Wink Saville
483767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
484767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Any address except the SC address (eg, originating address) See TS
485767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * 23.040 9.1.2.5
486767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
487767a662ecde33c3979bf02b793d392aca0403162Wink Saville        GsmSmsAddress getAddress() {
488767a662ecde33c3979bf02b793d392aca0403162Wink Saville            GsmSmsAddress ret;
489767a662ecde33c3979bf02b793d392aca0403162Wink Saville
490767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // "The Address-Length field is an integer representation of
491767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // the number field, i.e. excludes any semi octet containing only
492767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // fill bits."
493767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // The TOA field is not included as part of this
494767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int addressLength = pdu[cur] & 0xff;
495767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int lengthBytes = 2 + (addressLength + 1) / 2;
496767a662ecde33c3979bf02b793d392aca0403162Wink Saville
497767a662ecde33c3979bf02b793d392aca0403162Wink Saville            ret = new GsmSmsAddress(pdu, cur, lengthBytes);
498767a662ecde33c3979bf02b793d392aca0403162Wink Saville
499767a662ecde33c3979bf02b793d392aca0403162Wink Saville            cur += lengthBytes;
500767a662ecde33c3979bf02b793d392aca0403162Wink Saville
501767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return ret;
502767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
503767a662ecde33c3979bf02b793d392aca0403162Wink Saville
504767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
505767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Parses an SC timestamp and returns a currentTimeMillis()-style
506767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * timestamp
507767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
508767a662ecde33c3979bf02b793d392aca0403162Wink Saville
509767a662ecde33c3979bf02b793d392aca0403162Wink Saville        long getSCTimestampMillis() {
510767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TP-Service-Centre-Time-Stamp
511767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int year = IccUtils.bcdByteToInt(pdu[cur++]);
512767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int month = IccUtils.bcdByteToInt(pdu[cur++]);
513767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int day = IccUtils.bcdByteToInt(pdu[cur++]);
514767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int hour = IccUtils.bcdByteToInt(pdu[cur++]);
515767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int minute = IccUtils.bcdByteToInt(pdu[cur++]);
516767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int second = IccUtils.bcdByteToInt(pdu[cur++]);
517767a662ecde33c3979bf02b793d392aca0403162Wink Saville
518767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // For the timezone, the most significant bit of the
519767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // least signficant nibble is the sign byte
520767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // (meaning the max range of this field is 79 quarter-hours,
521767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // which is more than enough)
522767a662ecde33c3979bf02b793d392aca0403162Wink Saville
523767a662ecde33c3979bf02b793d392aca0403162Wink Saville            byte tzByte = pdu[cur++];
524767a662ecde33c3979bf02b793d392aca0403162Wink Saville
525767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Mask out sign bit.
526767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int timezoneOffset = IccUtils
527767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    .bcdByteToInt((byte) (tzByte & (~0x08)));
528767a662ecde33c3979bf02b793d392aca0403162Wink Saville
529767a662ecde33c3979bf02b793d392aca0403162Wink Saville            timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset
530767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    : -timezoneOffset;
531767a662ecde33c3979bf02b793d392aca0403162Wink Saville
532767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Time time = new Time(Time.TIMEZONE_UTC);
533767a662ecde33c3979bf02b793d392aca0403162Wink Saville
534767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // It's 2006.  Should I really support years < 2000?
535767a662ecde33c3979bf02b793d392aca0403162Wink Saville            time.year = year >= 90 ? year + 1900 : year + 2000;
536767a662ecde33c3979bf02b793d392aca0403162Wink Saville            time.month = month - 1;
537767a662ecde33c3979bf02b793d392aca0403162Wink Saville            time.monthDay = day;
538767a662ecde33c3979bf02b793d392aca0403162Wink Saville            time.hour = hour;
539767a662ecde33c3979bf02b793d392aca0403162Wink Saville            time.minute = minute;
540767a662ecde33c3979bf02b793d392aca0403162Wink Saville            time.second = second;
541767a662ecde33c3979bf02b793d392aca0403162Wink Saville
542767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Timezone offset is in quarter hours.
543767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000);
544767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
545767a662ecde33c3979bf02b793d392aca0403162Wink Saville
546767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
547767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Pulls the user data out of the PDU, and separates the payload from
548767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * the header if there is one.
549767a662ecde33c3979bf02b793d392aca0403162Wink Saville         *
550767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @param hasUserDataHeader true if there is a user data header
551767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @param dataInSeptets true if the data payload is in septets instead
552767a662ecde33c3979bf02b793d392aca0403162Wink Saville         *  of octets
553767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @return the number of septets or octets in the user data payload
554767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
555767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) {
556767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int offset = cur;
557767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int userDataLength = pdu[offset++] & 0xff;
558767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int headerSeptets = 0;
559767a662ecde33c3979bf02b793d392aca0403162Wink Saville
560767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (hasUserDataHeader) {
561767a662ecde33c3979bf02b793d392aca0403162Wink Saville                int userDataHeaderLength = pdu[offset++] & 0xff;
562767a662ecde33c3979bf02b793d392aca0403162Wink Saville
563767a662ecde33c3979bf02b793d392aca0403162Wink Saville                byte[] udh = new byte[userDataHeaderLength];
564767a662ecde33c3979bf02b793d392aca0403162Wink Saville                System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength);
565767a662ecde33c3979bf02b793d392aca0403162Wink Saville                userDataHeader = SmsHeader.parse(udh);
566767a662ecde33c3979bf02b793d392aca0403162Wink Saville                offset += userDataHeaderLength;
567767a662ecde33c3979bf02b793d392aca0403162Wink Saville
568767a662ecde33c3979bf02b793d392aca0403162Wink Saville                int headerBits = (userDataHeaderLength + 1) * 8;
569767a662ecde33c3979bf02b793d392aca0403162Wink Saville                headerSeptets = headerBits / 7;
570767a662ecde33c3979bf02b793d392aca0403162Wink Saville                headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
571767a662ecde33c3979bf02b793d392aca0403162Wink Saville                mUserDataSeptetPadding = (headerSeptets * 7) - headerBits;
572767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
573767a662ecde33c3979bf02b793d392aca0403162Wink Saville
574767a662ecde33c3979bf02b793d392aca0403162Wink Saville            /*
575767a662ecde33c3979bf02b793d392aca0403162Wink Saville             * Here we just create the user data length to be the remainder of
576767a662ecde33c3979bf02b793d392aca0403162Wink Saville             * the pdu minus the user data hearder. This is because the count
577767a662ecde33c3979bf02b793d392aca0403162Wink Saville             * could mean the number of uncompressed sepets if the userdata is
578767a662ecde33c3979bf02b793d392aca0403162Wink Saville             * encoded in 7-bit.
579767a662ecde33c3979bf02b793d392aca0403162Wink Saville             */
580767a662ecde33c3979bf02b793d392aca0403162Wink Saville            userData = new byte[pdu.length - offset];
581767a662ecde33c3979bf02b793d392aca0403162Wink Saville            System.arraycopy(pdu, offset, userData, 0, userData.length);
582767a662ecde33c3979bf02b793d392aca0403162Wink Saville            cur = offset;
583767a662ecde33c3979bf02b793d392aca0403162Wink Saville
584767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (dataInSeptets) {
585767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // Return the number of septets
586767a662ecde33c3979bf02b793d392aca0403162Wink Saville                return userDataLength - headerSeptets;
587767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
588767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // Return the number of octets
589767a662ecde33c3979bf02b793d392aca0403162Wink Saville                return userData.length;
590767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
591767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
592767a662ecde33c3979bf02b793d392aca0403162Wink Saville
593767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
594767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Returns the user data payload, not including the headers
595767a662ecde33c3979bf02b793d392aca0403162Wink Saville         *
596767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @return the user data payload, not including the headers
597767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
598767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte[] getUserData() {
599767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return userData;
600767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
601767a662ecde33c3979bf02b793d392aca0403162Wink Saville
602767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
603767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Returns the number of padding bits at the begining of the user data
604767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * array before the start of the septets.
605767a662ecde33c3979bf02b793d392aca0403162Wink Saville         *
606767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @return the number of padding bits at the begining of the user data
607767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * array before the start of the septets
608767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
609767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int getUserDataSeptetPadding() {
610767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return mUserDataSeptetPadding;
611767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
612767a662ecde33c3979bf02b793d392aca0403162Wink Saville
613767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
614767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Returns an object representing the user data headers
615767a662ecde33c3979bf02b793d392aca0403162Wink Saville         *
616767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @return an object representing the user data headers
617767a662ecde33c3979bf02b793d392aca0403162Wink Saville         *
618767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * {@hide}
619767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
620767a662ecde33c3979bf02b793d392aca0403162Wink Saville        SmsHeader getUserDataHeader() {
621767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return userDataHeader;
622767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
623767a662ecde33c3979bf02b793d392aca0403162Wink Saville
624767a662ecde33c3979bf02b793d392aca0403162Wink Saville/*
625767a662ecde33c3979bf02b793d392aca0403162Wink Saville        XXX Not sure what this one is supposed to be doing, and no one is using
626767a662ecde33c3979bf02b793d392aca0403162Wink Saville        it.
627767a662ecde33c3979bf02b793d392aca0403162Wink Saville        String getUserDataGSM8bit() {
628767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // System.out.println("remainder of pud:" +
629767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // HexDump.dumpHexString(pdu, cur, pdu.length - cur));
630767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int count = pdu[cur++] & 0xff;
631767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int size = pdu[cur++];
632767a662ecde33c3979bf02b793d392aca0403162Wink Saville
633767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // skip over header for now
634767a662ecde33c3979bf02b793d392aca0403162Wink Saville            cur += size;
635767a662ecde33c3979bf02b793d392aca0403162Wink Saville
636767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (pdu[cur - 1] == 0x01) {
637767a662ecde33c3979bf02b793d392aca0403162Wink Saville                int tid = pdu[cur++] & 0xff;
638767a662ecde33c3979bf02b793d392aca0403162Wink Saville                int type = pdu[cur++] & 0xff;
639767a662ecde33c3979bf02b793d392aca0403162Wink Saville
640767a662ecde33c3979bf02b793d392aca0403162Wink Saville                size = pdu[cur++] & 0xff;
641767a662ecde33c3979bf02b793d392aca0403162Wink Saville
642767a662ecde33c3979bf02b793d392aca0403162Wink Saville                int i = cur;
643767a662ecde33c3979bf02b793d392aca0403162Wink Saville
644767a662ecde33c3979bf02b793d392aca0403162Wink Saville                while (pdu[i++] != '\0') {
645767a662ecde33c3979bf02b793d392aca0403162Wink Saville                }
646767a662ecde33c3979bf02b793d392aca0403162Wink Saville
647767a662ecde33c3979bf02b793d392aca0403162Wink Saville                int length = i - cur;
648767a662ecde33c3979bf02b793d392aca0403162Wink Saville                String mimeType = new String(pdu, cur, length);
649767a662ecde33c3979bf02b793d392aca0403162Wink Saville
650767a662ecde33c3979bf02b793d392aca0403162Wink Saville                cur += length;
651767a662ecde33c3979bf02b793d392aca0403162Wink Saville
652767a662ecde33c3979bf02b793d392aca0403162Wink Saville                if (false) {
653767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    System.out.println("tid = 0x" + HexDump.toHexString(tid));
654767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    System.out.println("type = 0x" + HexDump.toHexString(type));
655767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    System.out.println("header size = " + size);
656767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    System.out.println("mimeType = " + mimeType);
657767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    System.out.println("remainder of header:" +
658767a662ecde33c3979bf02b793d392aca0403162Wink Saville                     HexDump.dumpHexString(pdu, cur, (size - mimeType.length())));
659767a662ecde33c3979bf02b793d392aca0403162Wink Saville                }
660767a662ecde33c3979bf02b793d392aca0403162Wink Saville
661767a662ecde33c3979bf02b793d392aca0403162Wink Saville                cur += size - mimeType.length();
662767a662ecde33c3979bf02b793d392aca0403162Wink Saville
663767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // System.out.println("data count = " + count + " cur = " + cur
664767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // + " :" + HexDump.dumpHexString(pdu, cur, pdu.length - cur));
665767a662ecde33c3979bf02b793d392aca0403162Wink Saville
666767a662ecde33c3979bf02b793d392aca0403162Wink Saville                MMSMessage msg = MMSMessage.parseEncoding(mContext, pdu, cur,
667767a662ecde33c3979bf02b793d392aca0403162Wink Saville                        pdu.length - cur);
668767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
669767a662ecde33c3979bf02b793d392aca0403162Wink Saville                System.out.println(new String(pdu, cur, pdu.length - cur - 1));
670767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
671767a662ecde33c3979bf02b793d392aca0403162Wink Saville
672767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return IccUtils.bytesToHexString(pdu);
673767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
674767a662ecde33c3979bf02b793d392aca0403162Wink Saville*/
675767a662ecde33c3979bf02b793d392aca0403162Wink Saville
676767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
677767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Interprets the user data payload as pack GSM 7bit characters, and
678767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * decodes them into a String.
679767a662ecde33c3979bf02b793d392aca0403162Wink Saville         *
680767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @param septetCount the number of septets in the user data payload
681767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @return a String with the decoded characters
682767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
683767a662ecde33c3979bf02b793d392aca0403162Wink Saville        String getUserDataGSM7Bit(int septetCount) {
684767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String ret;
685767a662ecde33c3979bf02b793d392aca0403162Wink Saville
686767a662ecde33c3979bf02b793d392aca0403162Wink Saville            ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount,
687767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    mUserDataSeptetPadding);
688767a662ecde33c3979bf02b793d392aca0403162Wink Saville
689767a662ecde33c3979bf02b793d392aca0403162Wink Saville            cur += (septetCount * 7) / 8;
690767a662ecde33c3979bf02b793d392aca0403162Wink Saville
691767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return ret;
692767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
693767a662ecde33c3979bf02b793d392aca0403162Wink Saville
694767a662ecde33c3979bf02b793d392aca0403162Wink Saville        /**
695767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * Interprets the user data payload as UCS2 characters, and
696767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * decodes them into a String.
697767a662ecde33c3979bf02b793d392aca0403162Wink Saville         *
698767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @param byteCount the number of bytes in the user data payload
699767a662ecde33c3979bf02b793d392aca0403162Wink Saville         * @return a String with the decoded characters
700767a662ecde33c3979bf02b793d392aca0403162Wink Saville         */
701767a662ecde33c3979bf02b793d392aca0403162Wink Saville        String getUserDataUCS2(int byteCount) {
702767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String ret;
703767a662ecde33c3979bf02b793d392aca0403162Wink Saville
704767a662ecde33c3979bf02b793d392aca0403162Wink Saville            try {
705767a662ecde33c3979bf02b793d392aca0403162Wink Saville                ret = new String(pdu, cur, byteCount, "utf-16");
706767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } catch (UnsupportedEncodingException ex) {
707767a662ecde33c3979bf02b793d392aca0403162Wink Saville                ret = "";
708767a662ecde33c3979bf02b793d392aca0403162Wink Saville                Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
709767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
710767a662ecde33c3979bf02b793d392aca0403162Wink Saville
711767a662ecde33c3979bf02b793d392aca0403162Wink Saville            cur += byteCount;
712767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return ret;
713767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
714767a662ecde33c3979bf02b793d392aca0403162Wink Saville
715767a662ecde33c3979bf02b793d392aca0403162Wink Saville        boolean moreDataPresent() {
716767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return (pdu.length > cur);
717767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
718767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
719767a662ecde33c3979bf02b793d392aca0403162Wink Saville
720767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
721767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public int getProtocolIdentifier() {
722767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return protocolIdentifier;
723767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
724767a662ecde33c3979bf02b793d392aca0403162Wink Saville
725767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
726767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isReplace() {
727767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return (protocolIdentifier & 0xc0) == 0x40
728767a662ecde33c3979bf02b793d392aca0403162Wink Saville                && (protocolIdentifier & 0x3f) > 0
729767a662ecde33c3979bf02b793d392aca0403162Wink Saville                && (protocolIdentifier & 0x3f) < 8;
730767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
731767a662ecde33c3979bf02b793d392aca0403162Wink Saville
732767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
733767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isCphsMwiMessage() {
734767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear()
735767a662ecde33c3979bf02b793d392aca0403162Wink Saville                || ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet();
736767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
737767a662ecde33c3979bf02b793d392aca0403162Wink Saville
738767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
739767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isMWIClearMessage() {
740767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (isMwi && (mwiSense == false)) {
741767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return true;
742767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
743767a662ecde33c3979bf02b793d392aca0403162Wink Saville
744767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return originatingAddress != null
745767a662ecde33c3979bf02b793d392aca0403162Wink Saville                && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear();
746767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
747767a662ecde33c3979bf02b793d392aca0403162Wink Saville
748767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
749767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isMWISetMessage() {
750767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (isMwi && (mwiSense == true)) {
751767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return true;
752767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
753767a662ecde33c3979bf02b793d392aca0403162Wink Saville
754767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return originatingAddress != null
755767a662ecde33c3979bf02b793d392aca0403162Wink Saville                && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet();
756767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
757767a662ecde33c3979bf02b793d392aca0403162Wink Saville
758767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
759767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isMwiDontStore() {
760767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (isMwi && mwiDontStore) {
761767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return true;
762767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
763767a662ecde33c3979bf02b793d392aca0403162Wink Saville
764767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (isCphsMwiMessage()) {
765767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // See CPHS 4.2 Section B.4.2.1
766767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // If the user data is a single space char, do not store
767767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // the message. Otherwise, store and display as usual
768767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (" ".equals(getMessageBody())) {
769767a662ecde33c3979bf02b793d392aca0403162Wink Saville                ;
770767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
771767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return true;
772767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
773767a662ecde33c3979bf02b793d392aca0403162Wink Saville
774767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return false;
775767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
776767a662ecde33c3979bf02b793d392aca0403162Wink Saville
777767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
778767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public int getStatus() {
779767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return status;
780767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
781767a662ecde33c3979bf02b793d392aca0403162Wink Saville
782767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
783767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isStatusReportMessage() {
784767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return isStatusReportMessage;
785767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
786767a662ecde33c3979bf02b793d392aca0403162Wink Saville
787767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
788767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isReplyPathPresent() {
789767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return replyPathPresent;
790767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
791767a662ecde33c3979bf02b793d392aca0403162Wink Saville
792767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
793767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6]
794767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format:
795767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * ME/TA converts each octet of TP data unit into two IRA character long
796767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * hexad number (e.g. octet with integer value 42 is presented to TE as two
797767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast,
798767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * something else...
799767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
800767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private void parsePdu(byte[] pdu) {
801767a662ecde33c3979bf02b793d392aca0403162Wink Saville        mPdu = pdu;
802767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Log.d(LOG_TAG, "raw sms mesage:");
803767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Log.d(LOG_TAG, s);
804767a662ecde33c3979bf02b793d392aca0403162Wink Saville
805767a662ecde33c3979bf02b793d392aca0403162Wink Saville        PduParser p = new PduParser(pdu);
806767a662ecde33c3979bf02b793d392aca0403162Wink Saville
807767a662ecde33c3979bf02b793d392aca0403162Wink Saville        scAddress = p.getSCAddress();
808767a662ecde33c3979bf02b793d392aca0403162Wink Saville
809767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (scAddress != null) {
810767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (Config.LOGD) Log.d(LOG_TAG, "SMS SC address: " + scAddress);
811767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
812767a662ecde33c3979bf02b793d392aca0403162Wink Saville
813767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TODO(mkf) support reply path, user data header indicator
814767a662ecde33c3979bf02b793d392aca0403162Wink Saville
815767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Message-Type-Indicator
816767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // 9.2.3
817767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int firstByte = p.getByte();
818767a662ecde33c3979bf02b793d392aca0403162Wink Saville
819767a662ecde33c3979bf02b793d392aca0403162Wink Saville        mti = firstByte & 0x3;
820767a662ecde33c3979bf02b793d392aca0403162Wink Saville        switch (mti) {
821767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Message-Type-Indicator
822767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // 9.2.3
823767a662ecde33c3979bf02b793d392aca0403162Wink Saville        case 0:
824767a662ecde33c3979bf02b793d392aca0403162Wink Saville            parseSmsDeliver(p, firstByte);
825767a662ecde33c3979bf02b793d392aca0403162Wink Saville            break;
826767a662ecde33c3979bf02b793d392aca0403162Wink Saville        case 2:
827767a662ecde33c3979bf02b793d392aca0403162Wink Saville            parseSmsStatusReport(p, firstByte);
828767a662ecde33c3979bf02b793d392aca0403162Wink Saville            break;
829767a662ecde33c3979bf02b793d392aca0403162Wink Saville        default:
830767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TODO(mkf) the rest of these
831767a662ecde33c3979bf02b793d392aca0403162Wink Saville            throw new RuntimeException("Unsupported message type");
832767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
833767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
834767a662ecde33c3979bf02b793d392aca0403162Wink Saville
835767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
836767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Parses a SMS-STATUS-REPORT message.
837767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
838767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param p A PduParser, cued past the first byte.
839767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param firstByte The first byte of the PDU, which contains MTI, etc.
840767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
841767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private void parseSmsStatusReport(PduParser p, int firstByte) {
842767a662ecde33c3979bf02b793d392aca0403162Wink Saville        isStatusReportMessage = true;
843767a662ecde33c3979bf02b793d392aca0403162Wink Saville
844767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Status-Report-Qualifier bit == 0 for SUBMIT
845767a662ecde33c3979bf02b793d392aca0403162Wink Saville        forSubmit = (firstByte & 0x20) == 0x00;
846767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Message-Reference
847767a662ecde33c3979bf02b793d392aca0403162Wink Saville        messageRef = p.getByte();
848767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Recipient-Address
849767a662ecde33c3979bf02b793d392aca0403162Wink Saville        recipientAddress = p.getAddress();
850767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Service-Centre-Time-Stamp
851767a662ecde33c3979bf02b793d392aca0403162Wink Saville        scTimeMillis = p.getSCTimestampMillis();
852767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Discharge-Time
853767a662ecde33c3979bf02b793d392aca0403162Wink Saville        dischargeTimeMillis = p.getSCTimestampMillis();
854767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Status
855767a662ecde33c3979bf02b793d392aca0403162Wink Saville        status = p.getByte();
856767a662ecde33c3979bf02b793d392aca0403162Wink Saville
857767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // The following are optional fields that may or may not be present.
858767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (p.moreDataPresent()) {
859767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TP-Parameter-Indicator
860767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int extraParams = p.getByte();
861767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int moreExtraParams = extraParams;
862767a662ecde33c3979bf02b793d392aca0403162Wink Saville            while ((moreExtraParams & 0x80) != 0) {
863767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // We only know how to parse a few extra parameters, all
864767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // indicated in the first TP-PI octet, so skip over any
865767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // additional TP-PI octets.
866767a662ecde33c3979bf02b793d392aca0403162Wink Saville                moreExtraParams = p.getByte();
867767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
868767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TP-Protocol-Identifier
869767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if ((extraParams & 0x01) != 0) {
870767a662ecde33c3979bf02b793d392aca0403162Wink Saville                protocolIdentifier = p.getByte();
871767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
872767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TP-Data-Coding-Scheme
873767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if ((extraParams & 0x02) != 0) {
874767a662ecde33c3979bf02b793d392aca0403162Wink Saville                dataCodingScheme = p.getByte();
875767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
876767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // TP-User-Data-Length (implies existence of TP-User-Data)
877767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if ((extraParams & 0x04) != 0) {
878767a662ecde33c3979bf02b793d392aca0403162Wink Saville                boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;
879767a662ecde33c3979bf02b793d392aca0403162Wink Saville                parseUserData(p, hasUserDataHeader);
880767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
881767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
882767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
883767a662ecde33c3979bf02b793d392aca0403162Wink Saville
884767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private void parseSmsDeliver(PduParser p, int firstByte) {
885767a662ecde33c3979bf02b793d392aca0403162Wink Saville        replyPathPresent = (firstByte & 0x80) == 0x80;
886767a662ecde33c3979bf02b793d392aca0403162Wink Saville
887767a662ecde33c3979bf02b793d392aca0403162Wink Saville        originatingAddress = p.getAddress();
888767a662ecde33c3979bf02b793d392aca0403162Wink Saville
889767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (originatingAddress != null) {
890767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
891767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    + originatingAddress.address);
892767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
893767a662ecde33c3979bf02b793d392aca0403162Wink Saville
894767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Protocol-Identifier (TP-PID)
895767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TS 23.040 9.2.3.9
896767a662ecde33c3979bf02b793d392aca0403162Wink Saville        protocolIdentifier = p.getByte();
897767a662ecde33c3979bf02b793d392aca0403162Wink Saville
898767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TP-Data-Coding-Scheme
899767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // see TS 23.038
900767a662ecde33c3979bf02b793d392aca0403162Wink Saville        dataCodingScheme = p.getByte();
901767a662ecde33c3979bf02b793d392aca0403162Wink Saville
902767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (Config.LOGV) {
903767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.v(LOG_TAG, "SMS TP-PID:" + protocolIdentifier
904767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    + " data coding scheme: " + dataCodingScheme);
905767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
906767a662ecde33c3979bf02b793d392aca0403162Wink Saville
907767a662ecde33c3979bf02b793d392aca0403162Wink Saville        scTimeMillis = p.getSCTimestampMillis();
908767a662ecde33c3979bf02b793d392aca0403162Wink Saville
909767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
910767a662ecde33c3979bf02b793d392aca0403162Wink Saville
911767a662ecde33c3979bf02b793d392aca0403162Wink Saville        boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;
912767a662ecde33c3979bf02b793d392aca0403162Wink Saville
913767a662ecde33c3979bf02b793d392aca0403162Wink Saville        parseUserData(p, hasUserDataHeader);
914767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
915767a662ecde33c3979bf02b793d392aca0403162Wink Saville
916767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
917767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Parses the User Data of an SMS.
918767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
919767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param p The current PduParser.
920767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param hasUserDataHeader Indicates whether a header is present in the
921767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *                          User Data.
922767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
923767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private void parseUserData(PduParser p, boolean hasUserDataHeader) {
924767a662ecde33c3979bf02b793d392aca0403162Wink Saville        boolean hasMessageClass = false;
925767a662ecde33c3979bf02b793d392aca0403162Wink Saville        boolean userDataCompressed = false;
926767a662ecde33c3979bf02b793d392aca0403162Wink Saville
927767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int encodingType = ENCODING_UNKNOWN;
928767a662ecde33c3979bf02b793d392aca0403162Wink Saville
929767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Look up the data encoding scheme
930767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if ((dataCodingScheme & 0x80) == 0) {
931767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Bits 7..4 == 0xxx
932767a662ecde33c3979bf02b793d392aca0403162Wink Saville            automaticDeletion = (0 != (dataCodingScheme & 0x40));
933767a662ecde33c3979bf02b793d392aca0403162Wink Saville            userDataCompressed = (0 != (dataCodingScheme & 0x20));
934767a662ecde33c3979bf02b793d392aca0403162Wink Saville            hasMessageClass = (0 != (dataCodingScheme & 0x10));
935767a662ecde33c3979bf02b793d392aca0403162Wink Saville
936767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (userDataCompressed) {
937767a662ecde33c3979bf02b793d392aca0403162Wink Saville                Log.w(LOG_TAG, "4 - Unsupported SMS data coding scheme "
938767a662ecde33c3979bf02b793d392aca0403162Wink Saville                        + "(compression) " + (dataCodingScheme & 0xff));
939767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
940767a662ecde33c3979bf02b793d392aca0403162Wink Saville                switch ((dataCodingScheme >> 2) & 0x3) {
941767a662ecde33c3979bf02b793d392aca0403162Wink Saville                case 0: // GSM 7 bit default alphabet
942767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    encodingType = ENCODING_7BIT;
943767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    break;
944767a662ecde33c3979bf02b793d392aca0403162Wink Saville
945767a662ecde33c3979bf02b793d392aca0403162Wink Saville                case 2: // UCS 2 (16bit)
946767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    encodingType = ENCODING_16BIT;
947767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    break;
948767a662ecde33c3979bf02b793d392aca0403162Wink Saville
949767a662ecde33c3979bf02b793d392aca0403162Wink Saville                case 1: // 8 bit data
950767a662ecde33c3979bf02b793d392aca0403162Wink Saville                case 3: // reserved
951767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme "
952767a662ecde33c3979bf02b793d392aca0403162Wink Saville                            + (dataCodingScheme & 0xff));
953767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    encodingType = ENCODING_8BIT;
954767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    break;
955767a662ecde33c3979bf02b793d392aca0403162Wink Saville                }
956767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
957767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else if ((dataCodingScheme & 0xf0) == 0xf0) {
958767a662ecde33c3979bf02b793d392aca0403162Wink Saville            automaticDeletion = false;
959767a662ecde33c3979bf02b793d392aca0403162Wink Saville            hasMessageClass = true;
960767a662ecde33c3979bf02b793d392aca0403162Wink Saville            userDataCompressed = false;
961767a662ecde33c3979bf02b793d392aca0403162Wink Saville
962767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (0 == (dataCodingScheme & 0x04)) {
963767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // GSM 7 bit default alphabet
964767a662ecde33c3979bf02b793d392aca0403162Wink Saville                encodingType = ENCODING_7BIT;
965767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
966767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // 8 bit data
967767a662ecde33c3979bf02b793d392aca0403162Wink Saville                encodingType = ENCODING_8BIT;
968767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
969767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else if ((dataCodingScheme & 0xF0) == 0xC0
970767a662ecde33c3979bf02b793d392aca0403162Wink Saville                || (dataCodingScheme & 0xF0) == 0xD0
971767a662ecde33c3979bf02b793d392aca0403162Wink Saville                || (dataCodingScheme & 0xF0) == 0xE0) {
972767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
973767a662ecde33c3979bf02b793d392aca0403162Wink Saville
974767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // 0xC0 == 7 bit, don't store
975767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // 0xD0 == 7 bit, store
976767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // 0xE0 == UCS-2, store
977767a662ecde33c3979bf02b793d392aca0403162Wink Saville
978767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if ((dataCodingScheme & 0xF0) == 0xE0) {
979767a662ecde33c3979bf02b793d392aca0403162Wink Saville                encodingType = ENCODING_16BIT;
980767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
981767a662ecde33c3979bf02b793d392aca0403162Wink Saville                encodingType = ENCODING_7BIT;
982767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
983767a662ecde33c3979bf02b793d392aca0403162Wink Saville
984767a662ecde33c3979bf02b793d392aca0403162Wink Saville            userDataCompressed = false;
985767a662ecde33c3979bf02b793d392aca0403162Wink Saville            boolean active = ((dataCodingScheme & 0x08) == 0x08);
986767a662ecde33c3979bf02b793d392aca0403162Wink Saville
987767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // bit 0x04 reserved
988767a662ecde33c3979bf02b793d392aca0403162Wink Saville
989767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if ((dataCodingScheme & 0x03) == 0x00) {
990767a662ecde33c3979bf02b793d392aca0403162Wink Saville                isMwi = true;
991767a662ecde33c3979bf02b793d392aca0403162Wink Saville                mwiSense = active;
992767a662ecde33c3979bf02b793d392aca0403162Wink Saville                mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0);
993767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
994767a662ecde33c3979bf02b793d392aca0403162Wink Saville                isMwi = false;
995767a662ecde33c3979bf02b793d392aca0403162Wink Saville
996767a662ecde33c3979bf02b793d392aca0403162Wink Saville                Log.w(LOG_TAG, "MWI for fax, email, or other "
997767a662ecde33c3979bf02b793d392aca0403162Wink Saville                        + (dataCodingScheme & 0xff));
998767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
999767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else {
1000767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme "
1001767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    + (dataCodingScheme & 0xff));
1002767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
1003767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1004767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // set both the user data and the user data header.
1005767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int count = p.constructUserData(hasUserDataHeader,
1006767a662ecde33c3979bf02b793d392aca0403162Wink Saville                encodingType == ENCODING_7BIT);
1007767a662ecde33c3979bf02b793d392aca0403162Wink Saville        this.userData = p.getUserData();
1008767a662ecde33c3979bf02b793d392aca0403162Wink Saville        this.userDataHeader = p.getUserDataHeader();
1009767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1010767a662ecde33c3979bf02b793d392aca0403162Wink Saville        switch (encodingType) {
1011767a662ecde33c3979bf02b793d392aca0403162Wink Saville        case ENCODING_UNKNOWN:
1012767a662ecde33c3979bf02b793d392aca0403162Wink Saville        case ENCODING_8BIT:
1013767a662ecde33c3979bf02b793d392aca0403162Wink Saville            messageBody = null;
1014767a662ecde33c3979bf02b793d392aca0403162Wink Saville            break;
1015767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1016767a662ecde33c3979bf02b793d392aca0403162Wink Saville        case ENCODING_7BIT:
1017767a662ecde33c3979bf02b793d392aca0403162Wink Saville            messageBody = p.getUserDataGSM7Bit(count);
1018767a662ecde33c3979bf02b793d392aca0403162Wink Saville            break;
1019767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1020767a662ecde33c3979bf02b793d392aca0403162Wink Saville        case ENCODING_16BIT:
1021767a662ecde33c3979bf02b793d392aca0403162Wink Saville            messageBody = p.getUserDataUCS2(count);
1022767a662ecde33c3979bf02b793d392aca0403162Wink Saville            break;
1023767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
1024767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1025767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'");
1026767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1027767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (messageBody != null) {
1028767a662ecde33c3979bf02b793d392aca0403162Wink Saville            parseMessageBody();
1029767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
1030767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1031767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (!hasMessageClass) {
1032767a662ecde33c3979bf02b793d392aca0403162Wink Saville            messageClass = MessageClass.UNKNOWN;
1033767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else {
1034767a662ecde33c3979bf02b793d392aca0403162Wink Saville            switch (dataCodingScheme & 0x3) {
1035767a662ecde33c3979bf02b793d392aca0403162Wink Saville            case 0:
1036767a662ecde33c3979bf02b793d392aca0403162Wink Saville                messageClass = MessageClass.CLASS_0;
1037767a662ecde33c3979bf02b793d392aca0403162Wink Saville                break;
1038767a662ecde33c3979bf02b793d392aca0403162Wink Saville            case 1:
1039767a662ecde33c3979bf02b793d392aca0403162Wink Saville                messageClass = MessageClass.CLASS_1;
1040767a662ecde33c3979bf02b793d392aca0403162Wink Saville                break;
1041767a662ecde33c3979bf02b793d392aca0403162Wink Saville            case 2:
1042767a662ecde33c3979bf02b793d392aca0403162Wink Saville                messageClass = MessageClass.CLASS_2;
1043767a662ecde33c3979bf02b793d392aca0403162Wink Saville                break;
1044767a662ecde33c3979bf02b793d392aca0403162Wink Saville            case 3:
1045767a662ecde33c3979bf02b793d392aca0403162Wink Saville                messageClass = MessageClass.CLASS_3;
1046767a662ecde33c3979bf02b793d392aca0403162Wink Saville                break;
1047767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
1048767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
1049767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
1050767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1051767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
1052767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * {@inheritDoc}
1053767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
1054767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public MessageClass getMessageClass() {
1055767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return messageClass;
1056767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
1057767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1058767a662ecde33c3979bf02b793d392aca0403162Wink Saville}
1059