CdmaSMSDispatcher.java revision 867641ece36e2fd17faaea79cf19506ab17177c6
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 com.android.internal.telephony.cdma;
18767a662ecde33c3979bf02b793d392aca0403162Wink Saville
19767a662ecde33c3979bf02b793d392aca0403162Wink Saville
20867641ece36e2fd17faaea79cf19506ab17177c6jshimport android.app.Activity;
21767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.app.PendingIntent;
22767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.content.ContentValues;
23767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.database.Cursor;
24767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.database.SQLException;
25767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.os.AsyncResult;
26767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.os.Message;
27867641ece36e2fd17faaea79cf19506ab17177c6jshimport android.provider.Telephony.Sms.Intents;
28767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.util.Config;
29767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport android.util.Log;
30767a662ecde33c3979bf02b793d392aca0403162Wink Saville
31867641ece36e2fd17faaea79cf19506ab17177c6jshimport com.android.internal.telephony.CommandsInterface;
32767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SmsHeader;
33767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SmsMessageBase;
34767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.SMSDispatcher;
35767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.cdma.SmsMessage;
36767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.telephony.cdma.sms.SmsEnvelope;
37767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport com.android.internal.util.HexDump;
38767a662ecde33c3979bf02b793d392aca0403162Wink Saville
39767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport java.io.ByteArrayOutputStream;
40767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport java.util.ArrayList;
41767a662ecde33c3979bf02b793d392aca0403162Wink Savilleimport java.util.HashMap;
42767a662ecde33c3979bf02b793d392aca0403162Wink Saville
43767a662ecde33c3979bf02b793d392aca0403162Wink Saville
44767a662ecde33c3979bf02b793d392aca0403162Wink Savillefinal class CdmaSMSDispatcher extends SMSDispatcher {
45767a662ecde33c3979bf02b793d392aca0403162Wink Saville    private static final String TAG = "CDMA";
46767a662ecde33c3979bf02b793d392aca0403162Wink Saville
4764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink    private CDMAPhone mCdmaPhone;
4864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink
49767a662ecde33c3979bf02b793d392aca0403162Wink Saville    CdmaSMSDispatcher(CDMAPhone phone) {
50767a662ecde33c3979bf02b793d392aca0403162Wink Saville        super(phone);
5164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        mCdmaPhone = phone;
52767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
53767a662ecde33c3979bf02b793d392aca0403162Wink Saville
54767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
55767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Called when a status report is received.  This should correspond to
56767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * a previously successful SEND.
57767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Is a special GSM function, should never be called in CDMA!!
58767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
59767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param ar AsyncResult passed into the message handler.  ar.result should
60767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *           be a String representing the status report PDU, as ASCII hex.
61767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
62767a662ecde33c3979bf02b793d392aca0403162Wink Saville    protected void handleStatusReport(AsyncResult ar) {
63767a662ecde33c3979bf02b793d392aca0403162Wink Saville        Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!");
64767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
65767a662ecde33c3979bf02b793d392aca0403162Wink Saville
66767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
67767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Dispatches an incoming SMS messages.
68767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
69767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param smsb the incoming message from the phone
70767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
71767a662ecde33c3979bf02b793d392aca0403162Wink Saville    protected void dispatchMessage(SmsMessageBase smsb) {
72767a662ecde33c3979bf02b793d392aca0403162Wink Saville
73767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // If sms is null, means there was a parsing error.
74767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // TODO: Should NAK this.
75767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (smsb == null) {
76767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return;
77767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
78767a662ecde33c3979bf02b793d392aca0403162Wink Saville
79767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Decode BD stream and set sms variables.
8064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        SmsMessage sms = (SmsMessage) smsb;
81767a662ecde33c3979bf02b793d392aca0403162Wink Saville        sms.parseSms();
8264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        int teleService = sms.getTeleService();
8364c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        boolean handled = false;
84767a662ecde33c3979bf02b793d392aca0403162Wink Saville
85767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Teleservices W(E)MT and VMN are handled together:
8664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        if ((teleService == SmsEnvelope.TELESERVICE_WMT)
8764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                || (teleService == SmsEnvelope.TELESERVICE_WEMT)
8864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                || (teleService == SmsEnvelope.TELESERVICE_VMN)) {
89767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // From here on we need decoded BD.
90767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Special case the message waiting indicator messages
91767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (sms.isMWISetMessage()) {
9264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                mCdmaPhone.updateMessageWaitingIndicator(true);
9364c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                handled |= sms.isMwiDontStore();
94767a662ecde33c3979bf02b793d392aca0403162Wink Saville                if (Config.LOGD) {
9564c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                    Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
96767a662ecde33c3979bf02b793d392aca0403162Wink Saville                }
97767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else if (sms.isMWIClearMessage()) {
9864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                mCdmaPhone.updateMessageWaitingIndicator(false);
9964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                handled |= sms.isMwiDontStore();
100767a662ecde33c3979bf02b793d392aca0403162Wink Saville                if (Config.LOGD) {
10164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                    Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
102767a662ecde33c3979bf02b793d392aca0403162Wink Saville                }
103767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
104767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
105767a662ecde33c3979bf02b793d392aca0403162Wink Saville
10664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        if (sms.getUserData() == null) {
107767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (Config.LOGD) {
108767a662ecde33c3979bf02b793d392aca0403162Wink Saville                Log.d(TAG, "Received SMS without user data");
109767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
11064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            handled = true;
111767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
112767a662ecde33c3979bf02b793d392aca0403162Wink Saville
113767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (handled) return;
114767a662ecde33c3979bf02b793d392aca0403162Wink Saville
115767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (SmsEnvelope.TELESERVICE_WAP == teleService){
116767a662ecde33c3979bf02b793d392aca0403162Wink Saville            processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress());
117767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return;
118767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
119767a662ecde33c3979bf02b793d392aca0403162Wink Saville
12064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        /**
12164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * TODO(cleanup): Why are we using a getter method for this
12264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * (and for so many other sms fields)?  Trivial getters and
12364c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * setters like this are direct violations of the style guide.
12464c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * If the purpose is to protect agaist writes (by not
12564c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * providing a setter) then any protection is illusory (and
12664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * hence bad) for cases where the values are not primitives,
12764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * such as this call for the header.  Since this is an issue
12864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * with the public API it cannot be changed easily, but maybe
12964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * something can be done eventually.
13064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         */
13164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        SmsHeader smsHeader = sms.getUserDataHeader();
13264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink
13364c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        /**
13464c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * TODO(cleanup): Since both CDMA and GSM use the same header
13564c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * format, this dispatch processing is naturally identical,
13664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * and code should probably not be replicated explicitly.
13764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         */
13864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        // See if message is partial or port addressed.
13964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        if ((smsHeader == null) || (smsHeader.concatRef == null)) {
14064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            // Message is not partial (not part of concatenated sequence).
141767a662ecde33c3979bf02b793d392aca0403162Wink Saville            byte[][] pdus = new byte[1][];
142767a662ecde33c3979bf02b793d392aca0403162Wink Saville            pdus[0] = sms.getPdu();
143767a662ecde33c3979bf02b793d392aca0403162Wink Saville
14431fd22923aaefc85652a5b5939c6d4aa6fa289e2jsh            if (smsHeader != null && smsHeader.portAddrs != null) {
14564c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
14664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                    // GSM-style WAP indication
147767a662ecde33c3979bf02b793d392aca0403162Wink Saville                    mWapPush.dispatchWapPdu(sms.getUserData());
148767a662ecde33c3979bf02b793d392aca0403162Wink Saville                }
14964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                // The message was sent to a port, so concoct a URI for it.
15064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
151767a662ecde33c3979bf02b793d392aca0403162Wink Saville            } else {
15264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                // Normal short and non-port-addressed message, dispatch it.
153767a662ecde33c3979bf02b793d392aca0403162Wink Saville                dispatchPdus(pdus);
154767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
155767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } else {
15664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            // Process the message part.
15764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
158767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
159767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
160767a662ecde33c3979bf02b793d392aca0403162Wink Saville
161767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /**
162767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * Processes inbound messages that are in the WAP-WDP PDU format. See
163767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * wap-259-wdp-20010614-a section 6.5 for details on the WAP-WDP PDU format.
164767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * WDP segments are gathered until a datagram completes and gets dispatched.
165767a662ecde33c3979bf02b793d392aca0403162Wink Saville     *
166767a662ecde33c3979bf02b793d392aca0403162Wink Saville     * @param pdu The WAP-WDP PDU segment
167767a662ecde33c3979bf02b793d392aca0403162Wink Saville     */
168767a662ecde33c3979bf02b793d392aca0403162Wink Saville    protected void processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) {
169767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int segment;
170767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int totalSegments;
171767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int index = 0;
172767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int msgType;
173767a662ecde33c3979bf02b793d392aca0403162Wink Saville
174767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int sourcePort;
175767a662ecde33c3979bf02b793d392aca0403162Wink Saville        int destinationPort;
176767a662ecde33c3979bf02b793d392aca0403162Wink Saville
177767a662ecde33c3979bf02b793d392aca0403162Wink Saville        msgType = pdu[index++];
178767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (msgType != 0){
179767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.w(TAG, "Received a WAP SMS which is not WDP. Discard.");
180767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return;
181767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
182767a662ecde33c3979bf02b793d392aca0403162Wink Saville        totalSegments = pdu[index++]; // >=1
183767a662ecde33c3979bf02b793d392aca0403162Wink Saville        segment = pdu[index++]; // >=0
184767a662ecde33c3979bf02b793d392aca0403162Wink Saville
185767a662ecde33c3979bf02b793d392aca0403162Wink Saville        //process WDP segment
186767a662ecde33c3979bf02b793d392aca0403162Wink Saville        sourcePort = (0xFF & pdu[index++]) << 8;
187767a662ecde33c3979bf02b793d392aca0403162Wink Saville        sourcePort |= 0xFF & pdu[index++];
188767a662ecde33c3979bf02b793d392aca0403162Wink Saville        destinationPort = (0xFF & pdu[index++]) << 8;
189767a662ecde33c3979bf02b793d392aca0403162Wink Saville        destinationPort |= 0xFF & pdu[index++];
190767a662ecde33c3979bf02b793d392aca0403162Wink Saville
191767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Lookup all other related parts
192767a662ecde33c3979bf02b793d392aca0403162Wink Saville        StringBuilder where = new StringBuilder("reference_number =");
193767a662ecde33c3979bf02b793d392aca0403162Wink Saville        where.append(referenceNumber);
194767a662ecde33c3979bf02b793d392aca0403162Wink Saville        where.append(" AND address = ?");
195767a662ecde33c3979bf02b793d392aca0403162Wink Saville        String[] whereArgs = new String[] {address};
196767a662ecde33c3979bf02b793d392aca0403162Wink Saville
197767a662ecde33c3979bf02b793d392aca0403162Wink Saville        Log.i(TAG, "Received WAP PDU. Type = " + msgType + ", originator = " + address
198767a662ecde33c3979bf02b793d392aca0403162Wink Saville                + ", src-port = " + sourcePort + ", dst-port = " + destinationPort
199767a662ecde33c3979bf02b793d392aca0403162Wink Saville                + ", ID = " + referenceNumber + ", segment# = " + segment + "/" + totalSegments);
200767a662ecde33c3979bf02b793d392aca0403162Wink Saville
201767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte[][] pdus = null;
202767a662ecde33c3979bf02b793d392aca0403162Wink Saville        Cursor cursor = null;
203767a662ecde33c3979bf02b793d392aca0403162Wink Saville        try {
204767a662ecde33c3979bf02b793d392aca0403162Wink Saville            cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null);
205767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int cursorCount = cursor.getCount();
206767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (cursorCount != totalSegments - 1) {
207767a662ecde33c3979bf02b793d392aca0403162Wink Saville                // We don't have all the parts yet, store this one away
208767a662ecde33c3979bf02b793d392aca0403162Wink Saville                ContentValues values = new ContentValues();
209767a662ecde33c3979bf02b793d392aca0403162Wink Saville                values.put("date", new Long(0));
210767a662ecde33c3979bf02b793d392aca0403162Wink Saville                values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index));
211767a662ecde33c3979bf02b793d392aca0403162Wink Saville                values.put("address", address);
212767a662ecde33c3979bf02b793d392aca0403162Wink Saville                values.put("reference_number", referenceNumber);
213767a662ecde33c3979bf02b793d392aca0403162Wink Saville                values.put("count", totalSegments);
214767a662ecde33c3979bf02b793d392aca0403162Wink Saville                values.put("sequence", segment);
215767a662ecde33c3979bf02b793d392aca0403162Wink Saville                values.put("destination_port", destinationPort);
216767a662ecde33c3979bf02b793d392aca0403162Wink Saville
217767a662ecde33c3979bf02b793d392aca0403162Wink Saville                mResolver.insert(mRawUri, values);
218767a662ecde33c3979bf02b793d392aca0403162Wink Saville
219767a662ecde33c3979bf02b793d392aca0403162Wink Saville                return;
220767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
221767a662ecde33c3979bf02b793d392aca0403162Wink Saville
222767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // All the parts are in place, deal with them
223767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int pduColumn = cursor.getColumnIndex("pdu");
224767a662ecde33c3979bf02b793d392aca0403162Wink Saville            int sequenceColumn = cursor.getColumnIndex("sequence");
225767a662ecde33c3979bf02b793d392aca0403162Wink Saville
226767a662ecde33c3979bf02b793d392aca0403162Wink Saville            pdus = new byte[totalSegments][];
227767a662ecde33c3979bf02b793d392aca0403162Wink Saville            for (int i = 0; i < cursorCount; i++) {
228767a662ecde33c3979bf02b793d392aca0403162Wink Saville                cursor.moveToNext();
229767a662ecde33c3979bf02b793d392aca0403162Wink Saville                int cursorSequence = (int)cursor.getLong(sequenceColumn);
230767a662ecde33c3979bf02b793d392aca0403162Wink Saville                pdus[cursorSequence] = HexDump.hexStringToByteArray(
231767a662ecde33c3979bf02b793d392aca0403162Wink Saville                        cursor.getString(pduColumn));
232767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
233767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // The last part will be added later
234767a662ecde33c3979bf02b793d392aca0403162Wink Saville
235767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Remove the parts from the database
236767a662ecde33c3979bf02b793d392aca0403162Wink Saville            mResolver.delete(mRawUri, where.toString(), whereArgs);
237767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } catch (SQLException e) {
238767a662ecde33c3979bf02b793d392aca0403162Wink Saville            Log.e(TAG, "Can't access multipart SMS database", e);
239767a662ecde33c3979bf02b793d392aca0403162Wink Saville            return;  // TODO: NACK the message or something, don't just discard.
240767a662ecde33c3979bf02b793d392aca0403162Wink Saville        } finally {
241767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (cursor != null) cursor.close();
242767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
243767a662ecde33c3979bf02b793d392aca0403162Wink Saville
244767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Build up the data stream
245767a662ecde33c3979bf02b793d392aca0403162Wink Saville        ByteArrayOutputStream output = new ByteArrayOutputStream();
246767a662ecde33c3979bf02b793d392aca0403162Wink Saville        for (int i = 0; i < totalSegments-1; i++) {
247767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // reassemble the (WSP-)pdu
248767a662ecde33c3979bf02b793d392aca0403162Wink Saville            output.write(pdus[i], 0, pdus[i].length);
249767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
250767a662ecde33c3979bf02b793d392aca0403162Wink Saville
251767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // This one isn't in the DB, so add it
252767a662ecde33c3979bf02b793d392aca0403162Wink Saville        output.write(pdu, index, pdu.length - index);
253767a662ecde33c3979bf02b793d392aca0403162Wink Saville
254767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte[] datagram = output.toByteArray();
255767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // Dispatch the PDU to applications
256767a662ecde33c3979bf02b793d392aca0403162Wink Saville        switch (destinationPort) {
257767a662ecde33c3979bf02b793d392aca0403162Wink Saville        case SmsHeader.PORT_WAP_PUSH:
258767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // Handle the PUSH
259767a662ecde33c3979bf02b793d392aca0403162Wink Saville            mWapPush.dispatchWapPdu(datagram);
260767a662ecde33c3979bf02b793d392aca0403162Wink Saville            break;
261767a662ecde33c3979bf02b793d392aca0403162Wink Saville
262767a662ecde33c3979bf02b793d392aca0403162Wink Saville        default:{
263767a662ecde33c3979bf02b793d392aca0403162Wink Saville            pdus = new byte[1][];
264767a662ecde33c3979bf02b793d392aca0403162Wink Saville            pdus[0] = datagram;
265767a662ecde33c3979bf02b793d392aca0403162Wink Saville            // The messages were sent to any other WAP port
266767a662ecde33c3979bf02b793d392aca0403162Wink Saville            dispatchPortAddressedPdus(pdus, destinationPort);
267767a662ecde33c3979bf02b793d392aca0403162Wink Saville            break;
268767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
269767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
270767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
271767a662ecde33c3979bf02b793d392aca0403162Wink Saville
272767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
27364c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink    protected void sendMultipartText(String destAddr, String scAddr,
274767a662ecde33c3979bf02b793d392aca0403162Wink Saville            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
275767a662ecde33c3979bf02b793d392aca0403162Wink Saville            ArrayList<PendingIntent> deliveryIntents) {
276767a662ecde33c3979bf02b793d392aca0403162Wink Saville
27764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        /**
27864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * TODO(cleanup): There is no real code difference between
27964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * this and the GSM version, and hence it should be moved to
28064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * the base class or consolidated somehow, provided calling
28164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         * the proper submitpdu stuff can be arranged.
28264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink         */
283767a662ecde33c3979bf02b793d392aca0403162Wink Saville
28464c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        int refNumber = getNextConcatenatedRef() & 0x00FF;
285767a662ecde33c3979bf02b793d392aca0403162Wink Saville
28664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
28764c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
28864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            concatRef.refNumber = refNumber;
28964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            concatRef.seqNumber = i + 1;  // 1-based sequence
29064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            concatRef.msgCount = msgCount;
29164c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            concatRef.isEightBits = true;
29264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            SmsHeader smsHeader = new SmsHeader();
29364c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            smsHeader.concatRef = concatRef;
294767a662ecde33c3979bf02b793d392aca0403162Wink Saville
29564c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            PendingIntent sentIntent = null;
296767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (sentIntents != null && sentIntents.size() > i) {
297767a662ecde33c3979bf02b793d392aca0403162Wink Saville                sentIntent = sentIntents.get(i);
298767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
29964c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink
30064c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            PendingIntent deliveryIntent = null;
301767a662ecde33c3979bf02b793d392aca0403162Wink Saville            if (deliveryIntents != null && deliveryIntents.size() > i) {
302767a662ecde33c3979bf02b793d392aca0403162Wink Saville                deliveryIntent = deliveryIntents.get(i);
303767a662ecde33c3979bf02b793d392aca0403162Wink Saville            }
304767a662ecde33c3979bf02b793d392aca0403162Wink Saville
30564c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(scAddr, destAddr,
30664c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                    parts.get(i), deliveryIntent != null, smsHeader);
307767a662ecde33c3979bf02b793d392aca0403162Wink Saville
30864c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink            sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
309767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
310767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
311767a662ecde33c3979bf02b793d392aca0403162Wink Saville
31264c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink    protected void sendSubmitPdu(SmsMessage.SubmitPdu submitPdu, PendingIntent sentIntent,
313767a662ecde33c3979bf02b793d392aca0403162Wink Saville            PendingIntent deliveryIntent) {
31464c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink        sendRawPdu(submitPdu.encodedScAddress, submitPdu.encodedMessage,
31564c499113a758cf80cddfd4d0183f944a1a6645aTammo Spalink                sentIntent, deliveryIntent);
316767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
317767a662ecde33c3979bf02b793d392aca0403162Wink Saville
318767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
319767a662ecde33c3979bf02b793d392aca0403162Wink Saville    protected void sendSms(SmsTracker tracker) {
320767a662ecde33c3979bf02b793d392aca0403162Wink Saville        HashMap map = tracker.mData;
321767a662ecde33c3979bf02b793d392aca0403162Wink Saville
322767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte smsc[] = (byte[]) map.get("smsc");
323767a662ecde33c3979bf02b793d392aca0403162Wink Saville        byte pdu[] = (byte[]) map.get("pdu");
324767a662ecde33c3979bf02b793d392aca0403162Wink Saville
325767a662ecde33c3979bf02b793d392aca0403162Wink Saville        Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
326767a662ecde33c3979bf02b793d392aca0403162Wink Saville
327767a662ecde33c3979bf02b793d392aca0403162Wink Saville        mCm.sendCdmaSms(pdu, reply);
328767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
329767a662ecde33c3979bf02b793d392aca0403162Wink Saville
330767a662ecde33c3979bf02b793d392aca0403162Wink Saville     /** {@inheritDoc} */
331767a662ecde33c3979bf02b793d392aca0403162Wink Saville    protected void sendMultipartSms (SmsTracker tracker) {
332767a662ecde33c3979bf02b793d392aca0403162Wink Saville        Log.d(TAG, "TODO: CdmaSMSDispatcher.sendMultipartSms not implemented");
333767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
334767a662ecde33c3979bf02b793d392aca0403162Wink Saville
335767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
336867641ece36e2fd17faaea79cf19506ab17177c6jsh    protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
337767a662ecde33c3979bf02b793d392aca0403162Wink Saville        // FIXME unit test leaves cm == null. this should change
338767a662ecde33c3979bf02b793d392aca0403162Wink Saville        if (mCm != null) {
339867641ece36e2fd17faaea79cf19506ab17177c6jsh            mCm.acknowledgeLastIncomingCdmaSms(success, resultToCause(result), response);
340767a662ecde33c3979bf02b793d392aca0403162Wink Saville        }
341767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
342767a662ecde33c3979bf02b793d392aca0403162Wink Saville
343767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
344767a662ecde33c3979bf02b793d392aca0403162Wink Saville    protected void activateCellBroadcastSms(int activate, Message response) {
345767a662ecde33c3979bf02b793d392aca0403162Wink Saville        mCm.activateCdmaBroadcastSms(activate, response);
346767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
347767a662ecde33c3979bf02b793d392aca0403162Wink Saville
348767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
349767a662ecde33c3979bf02b793d392aca0403162Wink Saville    protected void getCellBroadcastSmsConfig(Message response) {
350767a662ecde33c3979bf02b793d392aca0403162Wink Saville        mCm.getCdmaBroadcastConfig(response);
351767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
352767a662ecde33c3979bf02b793d392aca0403162Wink Saville
353767a662ecde33c3979bf02b793d392aca0403162Wink Saville    /** {@inheritDoc} */
354767a662ecde33c3979bf02b793d392aca0403162Wink Saville    protected void setCellBroadcastConfig(int[] configValuesArray, Message response) {
355767a662ecde33c3979bf02b793d392aca0403162Wink Saville        mCm.setCdmaBroadcastConfig(configValuesArray, response);
356767a662ecde33c3979bf02b793d392aca0403162Wink Saville    }
357767a662ecde33c3979bf02b793d392aca0403162Wink Saville
358867641ece36e2fd17faaea79cf19506ab17177c6jsh    private int resultToCause(int rc) {
359867641ece36e2fd17faaea79cf19506ab17177c6jsh        switch (rc) {
360867641ece36e2fd17faaea79cf19506ab17177c6jsh            case Activity.RESULT_OK:
361867641ece36e2fd17faaea79cf19506ab17177c6jsh            case Intents.RESULT_SMS_HANDLED:
362867641ece36e2fd17faaea79cf19506ab17177c6jsh                // Cause code is ignored on success.
363867641ece36e2fd17faaea79cf19506ab17177c6jsh                return 0;
364867641ece36e2fd17faaea79cf19506ab17177c6jsh            case Intents.RESULT_SMS_OUT_OF_MEMORY:
365867641ece36e2fd17faaea79cf19506ab17177c6jsh                return CommandsInterface.CDMA_SMS_FAIL_CAUSE_RESOURCE_SHORTAGE;
366867641ece36e2fd17faaea79cf19506ab17177c6jsh            case Intents.RESULT_SMS_GENERIC_ERROR:
367867641ece36e2fd17faaea79cf19506ab17177c6jsh            default:
368867641ece36e2fd17faaea79cf19506ab17177c6jsh                return CommandsInterface.CDMA_SMS_FAIL_CAUSE_OTHER_TERMINAL_PROBLEM;
369867641ece36e2fd17faaea79cf19506ab17177c6jsh        }
370867641ece36e2fd17faaea79cf19506ab17177c6jsh    }
371767a662ecde33c3979bf02b793d392aca0403162Wink Saville}
372