1767a662ecde33c3979bf02b793d392aca0403162Wink Saville/*
2767a662ecde33c3979bf02b793d392aca0403162Wink Saville * Copyright (C) 2008 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 android.telephony;
18767a662ecde33c3979bf02b793d392aca0403162Wink Saville
19767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.os.Parcel;
20fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalinkimport android.util.Log;
21767a662ecde33c3979bf02b793d392aca0403162Wink Saville
22767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.GsmAlphabet;
2364c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalinkimport com.android.internal.telephony.SmsHeader;
24767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SmsMessageBase;
25767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
26fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalinkimport com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
27fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink
28fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalinkimport java.lang.Math;
29fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalinkimport java.util.ArrayList;
300da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganeshimport java.util.Arrays;
31767a662ecde33c3979bf02b793d392aca0403162Wink Saville
32767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
33767a662ecde33c3979bf02b793d392aca0403162Wink Saville
34767a662ecde33c3979bf02b793d392aca0403162Wink Saville
35767a662ecde33c3979bf02b793d392aca0403162Wink Saville/**
36767a662ecde33c3979bf02b793d392aca0403162Wink Saville * A Short Message Service message.
37767a662ecde33c3979bf02b793d392aca0403162Wink Saville */
38767a662ecde33c3979bf02b793d392aca0403162Wink Savillepublic class SmsMessage {
39767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private static final String LOG_TAG = "SMS";
40767a662ecde33c3979bf02b793d392aca0403162Wink Saville
41767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
42767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * SMS Class enumeration.
43767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * See TS 23.038.
44767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
45767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
46767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public enum MessageClass{
47767a662ecde33c3979bf02b793d392aca0403162Wink Saville        UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
48767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
49767a662ecde33c3979bf02b793d392aca0403162Wink Saville
50fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink    /** User data text encoding code unit size */
51767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static final int ENCODING_UNKNOWN = 0;
52767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static final int ENCODING_7BIT = 1;
53767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static final int ENCODING_8BIT = 2;
54767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static final int ENCODING_16BIT = 3;
55b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee    /**
56b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee     * @hide This value is not defined in global standard. Only in Korea, this is used.
57b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee     */
58b55df4471ed55a0e91dee79304f3b1209ffa4b35Sang-il, Lee    public static final int ENCODING_KSC5601 = 4;
59767a662ecde33c3979bf02b793d392aca0403162Wink Saville
60767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** The maximum number of payload bytes per message */
61767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static final int MAX_USER_DATA_BYTES = 140;
62767a662ecde33c3979bf02b793d392aca0403162Wink Saville
63767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
64767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * The maximum number of payload bytes per message if a user data header
65767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * is present.  This assumes the header only contains the
66767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * CONCATENATED_8_BIT_REFERENCE element.
67767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
68767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134;
69767a662ecde33c3979bf02b793d392aca0403162Wink Saville
70767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** The maximum number of payload septets per message */
71767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static final int MAX_USER_DATA_SEPTETS = 160;
72767a662ecde33c3979bf02b793d392aca0403162Wink Saville
73767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
74767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * The maximum number of payload septets per message if a user data header
75767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * is present.  This assumes the header only contains the
76767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * CONCATENATED_8_BIT_REFERENCE element.
77767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
78767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
79767a662ecde33c3979bf02b793d392aca0403162Wink Saville
80b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /**
81b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * Indicates a 3GPP format SMS message.
82b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @hide pending API council approval
83b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     */
84b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    public static final String FORMAT_3GPP = "3gpp";
85b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
86b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /**
87b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * Indicates a 3GPP2 format SMS message.
88b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @hide pending API council approval
89b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     */
90b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    public static final String FORMAT_3GPP2 = "3gpp2";
91b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
92767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** Contains actual SmsMessage. Only public for debugging and for framework layer.
930da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     *
940da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     * @hide
950da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     */
96767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public SmsMessageBase mWrappedSmsMessage;
97767a662ecde33c3979bf02b793d392aca0403162Wink Saville
980da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh    public static class SubmitPdu {
99767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1000da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh        public byte[] encodedScAddress; // Null if not applicable.
1010da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh        public byte[] encodedMessage;
1020da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh
1030da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh        public String toString() {
1040da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh            return "SubmitPdu: encodedScAddress = "
1050da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh                    + Arrays.toString(encodedScAddress)
1060da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh                    + ", encodedMessage = "
1070da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh                    + Arrays.toString(encodedMessage);
108767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
109767a662ecde33c3979bf02b793d392aca0403162Wink Saville
1100da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh        /**
1110da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh         * @hide
1120da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh         */
113767a662ecde33c3979bf02b793d392aca0403162Wink Saville        protected SubmitPdu(SubmitPduBase spb) {
114767a662ecde33c3979bf02b793d392aca0403162Wink Saville            this.encodedMessage = spb.encodedMessage;
115767a662ecde33c3979bf02b793d392aca0403162Wink Saville            this.encodedScAddress = spb.encodedScAddress;
116767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
117767a662ecde33c3979bf02b793d392aca0403162Wink Saville
118767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
119767a662ecde33c3979bf02b793d392aca0403162Wink Saville
120767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private SmsMessage(SmsMessageBase smb) {
121767a662ecde33c3979bf02b793d392aca0403162Wink Saville        mWrappedSmsMessage = smb;
122767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
123767a662ecde33c3979bf02b793d392aca0403162Wink Saville
124767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
125767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Create an SmsMessage from a raw PDU.
126b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     *
127b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * <p><b>This method will soon be deprecated</b> and all applications which handle
128b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast
129b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * intent <b>must</b> now pass the new {@code format} String extra from the intent
130b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * into the new method {@code createFromPdu(byte[], String)} which takes an
131b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * extra format parameter. This is required in order to correctly decode the PDU on
132b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * devices that require support for both 3GPP and 3GPP2 formats at the same time,
133b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * such as dual-mode GSM/CDMA and CDMA/LTE phones.
134767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
135767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessage createFromPdu(byte[] pdu) {
1361938e314e34fb11ec5398716dfe9704cea66e31eWink Saville        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
137b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        String format = (PHONE_TYPE_CDMA == activePhone) ? FORMAT_3GPP2 : FORMAT_3GPP;
138b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        return createFromPdu(pdu, format);
139b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    }
140767a662ecde33c3979bf02b793d392aca0403162Wink Saville
141b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /**
142b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * Create an SmsMessage from a raw PDU with the specified message format. The
143b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * message format is passed in the {@code SMS_RECEIVED_ACTION} as the {@code format}
144b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
145b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
146b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     *
147b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @param pdu the message PDU from the SMS_RECEIVED_ACTION intent
148b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @param format the format extra from the SMS_RECEIVED_ACTION intent
149b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @hide pending API council approval
150b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     */
151b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    public static SmsMessage createFromPdu(byte[] pdu, String format) {
152b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        SmsMessageBase wrappedMessage;
153b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
154b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        if (FORMAT_3GPP2.equals(format)) {
155767a662ecde33c3979bf02b793d392aca0403162Wink Saville            wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
156b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        } else if (FORMAT_3GPP.equals(format)) {
157767a662ecde33c3979bf02b793d392aca0403162Wink Saville            wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
158b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        } else {
159b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            Log.e(LOG_TAG, "createFromPdu(): unsupported message format " + format);
160b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            return null;
161767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
162767a662ecde33c3979bf02b793d392aca0403162Wink Saville
163767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return new SmsMessage(wrappedMessage);
164767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
165767a662ecde33c3979bf02b793d392aca0403162Wink Saville
166767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
167767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
168767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * +CMT unsolicited response (PDU mode, of course)
169767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *  +CMT: [&lt;alpha>],<length><CR><LF><pdu>
170767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
171767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Only public for debugging and for RIL
172767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
173767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * {@hide}
174767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
175b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    public static SmsMessage newFromCMT(String[] lines) {
176b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        // received SMS in 3GPP format
177b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        SmsMessageBase wrappedMessage =
178b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines);
179767a662ecde33c3979bf02b793d392aca0403162Wink Saville
180767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return new SmsMessage(wrappedMessage);
181767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
182767a662ecde33c3979bf02b793d392aca0403162Wink Saville
183767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** @hide */
184767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessage newFromParcel(Parcel p) {
185b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        // received SMS in 3GPP2 format
186b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        SmsMessageBase wrappedMessage =
187b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p);
188767a662ecde33c3979bf02b793d392aca0403162Wink Saville
189767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return new SmsMessage(wrappedMessage);
190767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
191767a662ecde33c3979bf02b793d392aca0403162Wink Saville
192767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
193767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Create an SmsMessage from an SMS EF record.
194767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
195767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param index Index of SMS record. This should be index in ArrayList
196767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *              returned by SmsManager.getAllMessagesFromSim + 1.
197767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param data Record data.
198767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return An SmsMessage representing the record.
199767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
200767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @hide
201767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
202767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SmsMessage createFromEfRecord(int index, byte[] data) {
203767a662ecde33c3979bf02b793d392aca0403162Wink Saville        SmsMessageBase wrappedMessage;
2041938e314e34fb11ec5398716dfe9704cea66e31eWink Saville        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
205767a662ecde33c3979bf02b793d392aca0403162Wink Saville
206767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (PHONE_TYPE_CDMA == activePhone) {
207767a662ecde33c3979bf02b793d392aca0403162Wink Saville            wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
208767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    index, data);
209767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else {
210767a662ecde33c3979bf02b793d392aca0403162Wink Saville            wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
211767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    index, data);
212767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
213767a662ecde33c3979bf02b793d392aca0403162Wink Saville
21472fac6778119e42f39e00f5b7e36b7500893f45cTom Taylor        return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null;
215767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
216767a662ecde33c3979bf02b793d392aca0403162Wink Saville
217767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
218767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
219767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * length in bytes (not hex chars) less the SMSC header
220b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     *
221b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * FIXME: This method is only used by a CTS test case that isn't run on CDMA devices.
222b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * We should probably deprecate it and remove the obsolete test case.
223767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
224767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static int getTPLayerLengthForPDU(String pdu) {
2251938e314e34fb11ec5398716dfe9704cea66e31eWink Saville        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
226767a662ecde33c3979bf02b793d392aca0403162Wink Saville
227767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (PHONE_TYPE_CDMA == activePhone) {
228767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu);
229767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else {
230767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu);
231767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
232767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
233767a662ecde33c3979bf02b793d392aca0403162Wink Saville
234fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink    /*
235fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * TODO(cleanup): It would make some sense if the result of
236633dfb6da6d70cb369797b42df4bf046fdb3a07fJake Hamby     * preprocessing a message to determine the proper encoding (i.e.
237633dfb6da6d70cb369797b42df4bf046fdb3a07fJake Hamby     * the resulting data structure from calculateLength) could be
238fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * passed as an argument to the actual final encoding function.
239fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * This would better ensure that the logic behind size calculation
240fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * actually matched the encoding.
241fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     */
242fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink
243767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
244767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Calculates the number of SMS's required to encode the message body and
245a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink     * the number of characters remaining until the next message.
246767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
247a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink     * @param msgBody the message to encode
248a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink     * @param use7bitOnly if true, characters that are not part of the
249a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink     *         radio-specific 7-bit encoding are counted as single
250a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink     *         space chars.  If false, and if the messageBody contains
251a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink     *         non-7-bit encodable characters, length is calculated
252a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink     *         using a 16-bit encoding.
253fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * @return an int[4] with int[0] being the number of SMS's
254fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     *         required, int[1] the number of code units used, and
255fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     *         int[2] is the number of code units remaining until the
256fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     *         next message. int[3] is an indicator of the encoding
257fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     *         code unit size (see the ENCODING_* definitions in this
258fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     *         class).
259767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
260a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink    public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) {
2611938e314e34fb11ec5398716dfe9704cea66e31eWink Saville        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
262fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
2635e5b8c45dbb87be5468821ed298747ab065d73a6Tammo Spalink            com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly) :
2645e5b8c45dbb87be5468821ed298747ab065d73a6Tammo Spalink            com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
265767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int ret[] = new int[4];
266fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        ret[0] = ted.msgCount;
267fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        ret[1] = ted.codeUnitCount;
268fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        ret[2] = ted.codeUnitsRemaining;
269fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        ret[3] = ted.codeUnitSize;
270fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        return ret;
271fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink    }
272767a662ecde33c3979bf02b793d392aca0403162Wink Saville
273fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink    /**
274fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * Divide a message text into several fragments, none bigger than
275fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * the maximum SMS message text size.
276fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     *
277fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * @param text text, must not be null.
278fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     * @return an <code>ArrayList</code> of strings that, in order,
279fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     *   comprise the original msg text
2800da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     *
2810da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     * @hide
282fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink     */
283fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink    public static ArrayList<String> fragmentText(String text) {
2841938e314e34fb11ec5398716dfe9704cea66e31eWink Saville        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
285fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
2865e5b8c45dbb87be5468821ed298747ab065d73a6Tammo Spalink            com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false) :
2875e5b8c45dbb87be5468821ed298747ab065d73a6Tammo Spalink            com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false);
288fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink
289fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        // TODO(cleanup): The code here could be rolled into the logic
290fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        // below cleanly if these MAX_* constants were defined more
291fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        // flexibly...
292fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink
293fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        int limit;
294141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi        if (ted.codeUnitSize == ENCODING_7BIT) {
295141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            int udhLength;
296141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            if (ted.languageTable != 0 && ted.languageShiftTable != 0) {
297141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi                udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;
298141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {
299141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi                udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;
300141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            } else {
301141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi                udhLength = 0;
302141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            }
303141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi
304141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            if (ted.msgCount > 1) {
305141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi                udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE;
306141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            }
307141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi
308141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            if (udhLength != 0) {
309141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi                udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;
310141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            }
311141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi
312141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            limit = MAX_USER_DATA_SEPTETS - udhLength;
313a94945d3a1cf23caf33759eb1de84195d3fcb37bTammo Spalink        } else {
314141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            if (ted.msgCount > 1) {
315141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi                limit = MAX_USER_DATA_BYTES_WITH_HEADER;
316141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            } else {
317141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi                limit = MAX_USER_DATA_BYTES;
318141da403c0ad2d06b8f55e737ddf5d9e2b64c536bi            }
319767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
320767a662ecde33c3979bf02b793d392aca0403162Wink Saville
321fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        int pos = 0;  // Index in code units.
322fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        int textLen = text.length();
323fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        ArrayList<String> result = new ArrayList<String>(ted.msgCount);
324fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        while (pos < textLen) {
325fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink            int nextPos = 0;  // Counts code units.
326fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink            if (ted.codeUnitSize == ENCODING_7BIT) {
32795434bfaee62161ce02012c6424f0c0c8fffccb5Tammo Spalink                if (activePhone == PHONE_TYPE_CDMA && ted.msgCount == 1) {
32895434bfaee62161ce02012c6424f0c0c8fffccb5Tammo Spalink                    // For a singleton CDMA message, the encoding must be ASCII...
32995434bfaee62161ce02012c6424f0c0c8fffccb5Tammo Spalink                    nextPos = pos + Math.min(limit, textLen - pos);
33095434bfaee62161ce02012c6424f0c0c8fffccb5Tammo Spalink                } else {
33195434bfaee62161ce02012c6424f0c0c8fffccb5Tammo Spalink                    // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).
332b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby                    nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit,
333b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby                            ted.languageTable, ted.languageShiftTable);
33495434bfaee62161ce02012c6424f0c0c8fffccb5Tammo Spalink                }
335fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink            } else {  // Assume unicode.
336fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink                nextPos = pos + Math.min(limit / 2, textLen - pos);
337fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink            }
338fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink            if ((nextPos <= pos) || (nextPos > textLen)) {
339fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink                Log.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
340fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink                          nextPos + " >= " + textLen + ")");
341fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink                break;
342fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink            }
343fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink            result.add(text.substring(pos, nextPos));
344fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink            pos = nextPos;
345fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        }
346fc78f358cb1d1cee99758bcd6ef998a122ef27c9Tammo Spalink        return result;
347767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
348767a662ecde33c3979bf02b793d392aca0403162Wink Saville
349767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
350767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Calculates the number of SMS's required to encode the message body and
351767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * the number of characters remaining until the next message, given the
352767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * current encoding.
353767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
354767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param messageBody the message to encode
3550da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     * @param use7bitOnly if true, characters that are not part of the radio
3560da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     *         specific (GSM / CDMA) alphabet encoding are converted to as a
3570da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     *         single space characters. If false, a messageBody containing
3580da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     *         non-GSM or non-CDMA alphabet characters are encoded using
3590da3bdb476086db02a1076780676b21e239c79d6Jaikumar Ganesh     *         16-bit encoding.
360767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return an int[4] with int[0] being the number of SMS's required, int[1]
361767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         the number of code units used, and int[2] is the number of code
362767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         units remaining until the next message. int[3] is the encoding
363767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         type that should be used for the message.
364767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
365767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
366767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return calculateLength((CharSequence)messageBody, use7bitOnly);
367767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
368767a662ecde33c3979bf02b793d392aca0403162Wink Saville
3691f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink    /*
3701f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * TODO(cleanup): It looks like there is now no useful reason why
3711f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * apps should generate pdus themselves using these routines,
3721f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * instead of handing the raw data to SMSDispatcher (and thereby
3731f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * have the phone process do the encoding).  Moreover, CDMA now
3741f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * has shared state (in the form of the msgId system property)
3751f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * which can only be modified by the phone process, and hence
3761f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * makes the output of these routines incorrect.  Since they now
3771f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * serve no purpose, they should probably just return null
3781f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * directly, and be deprecated.  Going further in that direction,
3791f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * the above parsers of serialized pdu data should probably also
3801f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * be gotten rid of, hiding all but the necessarily visible
3811f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * structured data from client apps.  A possible concern with
3821f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * doing this is that apps may be using these routines to generate
3831f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * pdus that are then sent elsewhere, some network server, for
3841f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * example, and that always returning null would thereby break
3851f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     * otherwise useful apps.
3861f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink     */
3871f952a178db86559ff4bab79c4a9b5fae18096bfTammo Spalink
388767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
389b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby     * Get an SMS-SUBMIT PDU for a destination address and a message.
390b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby     * This method will not attempt to use any GSM national language 7 bit encodings.
391767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
392767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param scAddress Service Centre address.  Null means use default.
393767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return a <code>SubmitPdu</code> containing the encoded SC
394767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         address, if applicable, and the encoded message.
395767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         Returns null on encode error.
396767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
397767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SubmitPdu getSubmitPdu(String scAddress,
398767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String destinationAddress, String message, boolean statusReportRequested) {
399767a662ecde33c3979bf02b793d392aca0403162Wink Saville        SubmitPduBase spb;
4001938e314e34fb11ec5398716dfe9704cea66e31eWink Saville        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
401767a662ecde33c3979bf02b793d392aca0403162Wink Saville
402767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (PHONE_TYPE_CDMA == activePhone) {
403767a662ecde33c3979bf02b793d392aca0403162Wink Saville            spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
40464c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                    destinationAddress, message, statusReportRequested, null);
405767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else {
406767a662ecde33c3979bf02b793d392aca0403162Wink Saville            spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
407767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    destinationAddress, message, statusReportRequested);
408767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
409767a662ecde33c3979bf02b793d392aca0403162Wink Saville
410767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return new SubmitPdu(spb);
411767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
412767a662ecde33c3979bf02b793d392aca0403162Wink Saville
413767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
414b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby     * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
415b49a73dfc4c9817bba1f227e9330555acdf9b56fJake Hamby     * This method will not attempt to use any GSM national language 7 bit encodings.
416767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
417767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param scAddress Service Centre address. null == use default
418767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param destinationAddress the address of the destination for the message
419767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param destinationPort the port to deliver the message to at the
420767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *        destination
421633dfb6da6d70cb369797b42df4bf046fdb3a07fJake Hamby     * @param data the data for the message
422767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return a <code>SubmitPdu</code> containing the encoded SC
423767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         address, if applicable, and the encoded message.
424767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         Returns null on encode error.
425767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
426767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public static SubmitPdu getSubmitPdu(String scAddress,
427767a662ecde33c3979bf02b793d392aca0403162Wink Saville            String destinationAddress, short destinationPort, byte[] data,
428767a662ecde33c3979bf02b793d392aca0403162Wink Saville            boolean statusReportRequested) {
429767a662ecde33c3979bf02b793d392aca0403162Wink Saville        SubmitPduBase spb;
4301938e314e34fb11ec5398716dfe9704cea66e31eWink Saville        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
431767a662ecde33c3979bf02b793d392aca0403162Wink Saville
432767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (PHONE_TYPE_CDMA == activePhone) {
433767a662ecde33c3979bf02b793d392aca0403162Wink Saville            spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
434767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    destinationAddress, destinationPort, data, statusReportRequested);
435767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else {
436767a662ecde33c3979bf02b793d392aca0403162Wink Saville            spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
437767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    destinationAddress, destinationPort, data, statusReportRequested);
438767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
439767a662ecde33c3979bf02b793d392aca0403162Wink Saville
440767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return new SubmitPdu(spb);
441767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
442767a662ecde33c3979bf02b793d392aca0403162Wink Saville
443767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
444767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the address of the SMS service center that relayed this message
445767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * or null if there is none.
446767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
447767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public String getServiceCenterAddress() {
448767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getServiceCenterAddress();
449767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
450767a662ecde33c3979bf02b793d392aca0403162Wink Saville
451767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
452767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the originating address (sender) of this SMS message in String
453767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * form or null if unavailable
454767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
455767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public String getOriginatingAddress() {
456767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getOriginatingAddress();
457767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
458767a662ecde33c3979bf02b793d392aca0403162Wink Saville
459767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
460767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the originating address, or email from address if this message
461767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * was from an email gateway. Returns null if originating address
462767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * unavailable.
463767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
464767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public String getDisplayOriginatingAddress() {
465767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getDisplayOriginatingAddress();
466767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
467767a662ecde33c3979bf02b793d392aca0403162Wink Saville
468767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
469767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the message body as a String, if it exists and is text based.
470767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return message body is there is one, otherwise null
471767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
472767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public String getMessageBody() {
473767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getMessageBody();
474767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
475767a662ecde33c3979bf02b793d392aca0403162Wink Saville
476767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
477767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the class of this message.
478767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
479767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public MessageClass getMessageClass() {
480767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getMessageClass();
481767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
482767a662ecde33c3979bf02b793d392aca0403162Wink Saville
483767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
484767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the message body, or email message body if this message was from
485767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * an email gateway. Returns null if message body unavailable.
486767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
487767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public String getDisplayMessageBody() {
488767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getDisplayMessageBody();
489767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
490767a662ecde33c3979bf02b793d392aca0403162Wink Saville
491767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
492767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Unofficial convention of a subject line enclosed in parens empty string
493767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * if not present
494767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
495767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public String getPseudoSubject() {
496767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getPseudoSubject();
497767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
498767a662ecde33c3979bf02b793d392aca0403162Wink Saville
499767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
500767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the service centre timestamp in currentTimeMillis() format
501767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
502767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public long getTimestampMillis() {
503767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getTimestampMillis();
504767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
505767a662ecde33c3979bf02b793d392aca0403162Wink Saville
506767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
507767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns true if message is an email.
508767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
509767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return true if this message came through an email gateway and email
510767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         sender / subject / parsed body are available
511767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
512767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isEmail() {
513767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.isEmail();
514767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
515767a662ecde33c3979bf02b793d392aca0403162Wink Saville
516767a662ecde33c3979bf02b793d392aca0403162Wink Saville     /**
517767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return if isEmail() is true, body of the email sent through the gateway.
518767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         null otherwise
519767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
520767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public String getEmailBody() {
521767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getEmailBody();
522767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
523767a662ecde33c3979bf02b793d392aca0403162Wink Saville
524767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
525767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return if isEmail() is true, email from address of email sent through
526767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         the gateway. null otherwise
527767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
528767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public String getEmailFrom() {
529767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getEmailFrom();
530767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
531767a662ecde33c3979bf02b793d392aca0403162Wink Saville
532767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
533767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Get protocol identifier.
534767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
535767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public int getProtocolIdentifier() {
536767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getProtocolIdentifier();
537767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
538767a662ecde33c3979bf02b793d392aca0403162Wink Saville
539767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
540767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
541767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * SMS
542767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
543767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isReplace() {
544767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.isReplace();
545767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
546767a662ecde33c3979bf02b793d392aca0403162Wink Saville
547767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
548767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns true for CPHS MWI toggle message.
549767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
550767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
551767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         B.4.2
552767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
553767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isCphsMwiMessage() {
554767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.isCphsMwiMessage();
555767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
556767a662ecde33c3979bf02b793d392aca0403162Wink Saville
557767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
558767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * returns true if this message is a CPHS voicemail / message waiting
559767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * indicator (MWI) clear message
560767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
561767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isMWIClearMessage() {
562767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.isMWIClearMessage();
563767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
564767a662ecde33c3979bf02b793d392aca0403162Wink Saville
565767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
566767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * returns true if this message is a CPHS voicemail / message waiting
567767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * indicator (MWI) set message
568767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
569767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isMWISetMessage() {
570767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.isMWISetMessage();
571767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
572767a662ecde33c3979bf02b793d392aca0403162Wink Saville
573767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
574767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * returns true if this message is a "Message Waiting Indication Group:
575767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Discard Message" notification and should not be stored.
576767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
577767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isMwiDontStore() {
578767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.isMwiDontStore();
579767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
580767a662ecde33c3979bf02b793d392aca0403162Wink Saville
581767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
582767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * returns the user data section minus the user data header if one was
583767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * present.
584767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
585767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public byte[] getUserData() {
586767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getUserData();
587767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
588767a662ecde33c3979bf02b793d392aca0403162Wink Saville
589641bb3d8dfd72f57356d39ef00256d6077c9e235Tammo Spalink    /**
590767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the raw PDU for the message.
591767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
592767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return the raw PDU for the message.
593767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
594767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public byte[] getPdu() {
595767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getPdu();
596767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
597767a662ecde33c3979bf02b793d392aca0403162Wink Saville
598767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
599767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the status of the message on the SIM (read, unread, sent, unsent).
600767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
601767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return the status of the message on the SIM.  These are:
602767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_SIM_FREE
603767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_SIM_READ
604767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_SIM_UNREAD
605767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_SIM_SEND
606767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_SIM_UNSENT
607767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @deprecated Use getStatusOnIcc instead.
608767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
609767a662ecde33c3979bf02b793d392aca0403162Wink Saville    @Deprecated public int getStatusOnSim() {
610767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getStatusOnIcc();
611767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
612767a662ecde33c3979bf02b793d392aca0403162Wink Saville
613767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
614767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the status of the message on the ICC (read, unread, sent, unsent).
615767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
616767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return the status of the message on the ICC.  These are:
617767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_ICC_FREE
618767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_ICC_READ
619767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_ICC_UNREAD
620767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_ICC_SEND
621767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsManager.STATUS_ON_ICC_UNSENT
622767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
623767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public int getStatusOnIcc() {
624767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getStatusOnIcc();
625767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
626767a662ecde33c3979bf02b793d392aca0403162Wink Saville
627767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
628767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the record index of the message on the SIM (1-based index).
629767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return the record index of the message on the SIM, or -1 if this
630767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsMessage was not created from a SIM SMS EF record.
631767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @deprecated Use getIndexOnIcc instead.
632767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
633767a662ecde33c3979bf02b793d392aca0403162Wink Saville    @Deprecated public int getIndexOnSim() {
634767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getIndexOnIcc();
635767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
636767a662ecde33c3979bf02b793d392aca0403162Wink Saville
637767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
638767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns the record index of the message on the ICC (1-based index).
639767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return the record index of the message on the ICC, or -1 if this
640767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         SmsMessage was not created from a ICC SMS EF record.
641767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
642767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public int getIndexOnIcc() {
643767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getIndexOnIcc();
644767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
645767a662ecde33c3979bf02b793d392aca0403162Wink Saville
646767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
647767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * GSM:
648767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * For an SMS-STATUS-REPORT message, this returns the status field from
649767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * the status report.  This field indicates the status of a previously
650767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * submitted SMS, if requested.  See TS 23.040, 9.2.3.15 TP-Status for a
651767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * description of values.
652767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * CDMA:
653767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * For not interfering with status codes from GSM, the value is
654767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * shifted to the bits 31-16.
655767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * The value is composed of an error class (bits 25-24) and a status code (bits 23-16).
656767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Possible codes are described in C.S0015-B, v2.0, 4.5.21.
657767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
658767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @return 0 indicates the previously sent message was received.
659767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21
660767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *         for a description of other possible values.
661767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
662767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public int getStatus() {
663767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.getStatus();
664767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
665767a662ecde33c3979bf02b793d392aca0403162Wink Saville
666767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
667767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Return true iff the message is a SMS-STATUS-REPORT message.
668767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
669767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isStatusReportMessage() {
670767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.isStatusReportMessage();
671767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
672767a662ecde33c3979bf02b793d392aca0403162Wink Saville
673767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
674767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Returns true iff the <code>TP-Reply-Path</code> bit is set in
675767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * this message.
676767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
677767a662ecde33c3979bf02b793d392aca0403162Wink Saville    public boolean isReplyPathPresent() {
678767a662ecde33c3979bf02b793d392aca0403162Wink Saville        return mWrappedSmsMessage.isReplyPathPresent();
679767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
680767a662ecde33c3979bf02b793d392aca0403162Wink Saville}
681