GsmSMSDispatcher.java revision 0d4bcdf379842af4b6304809156971e926f374f0
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony.gsm;
18
19import android.app.Activity;
20import android.app.PendingIntent;
21import android.app.PendingIntent.CanceledException;
22import android.content.Intent;
23import android.os.AsyncResult;
24import android.os.Message;
25import android.provider.Telephony.Sms;
26import android.provider.Telephony.Sms.Intents;
27import android.telephony.Rlog;
28
29import com.android.internal.telephony.GsmAlphabet;
30import com.android.internal.telephony.PhoneBase;
31import com.android.internal.telephony.SMSDispatcher;
32import com.android.internal.telephony.SmsConstants;
33import com.android.internal.telephony.SmsHeader;
34import com.android.internal.telephony.SmsUsageMonitor;
35import com.android.internal.telephony.uicc.IccUtils;
36
37import java.util.HashMap;
38
39public final class GsmSMSDispatcher extends SMSDispatcher {
40    private static final String TAG = "GsmSMSDispatcher";
41
42    /** Status report received */
43    private static final int EVENT_NEW_SMS_STATUS_REPORT = 100;
44
45    public GsmSMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor) {
46        super(phone, usageMonitor);
47        mCi.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
48    }
49
50    @Override
51    public void dispose() {
52        super.dispose();
53        mCi.unSetOnSmsStatus(this);
54    }
55
56    @Override
57    protected String getFormat() {
58        return SmsConstants.FORMAT_3GPP;
59    }
60
61    /**
62     * Handles 3GPP format-specific events coming from the phone stack.
63     * Other events are handled by {@link SMSDispatcher#handleMessage}.
64     *
65     * @param msg the message to handle
66     */
67    @Override
68    public void handleMessage(Message msg) {
69        switch (msg.what) {
70        case EVENT_NEW_SMS_STATUS_REPORT:
71            handleStatusReport((AsyncResult) msg.obj);
72            break;
73
74        default:
75            super.handleMessage(msg);
76        }
77    }
78
79    /**
80     * Called when a status report is received.  This should correspond to
81     * a previously successful SEND.
82     *
83     * @param ar AsyncResult passed into the message handler.  ar.result should
84     *           be a String representing the status report PDU, as ASCII hex.
85     */
86    private void handleStatusReport(AsyncResult ar) {
87        String pduString = (String) ar.result;
88        SmsMessage sms = SmsMessage.newFromCDS(pduString);
89
90        if (sms != null) {
91            int tpStatus = sms.getStatus();
92            int messageRef = sms.mMessageRef;
93            for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
94                SmsTracker tracker = deliveryPendingList.get(i);
95                if (tracker.mMessageRef == messageRef) {
96                    // Found it.  Remove from list and broadcast.
97                    if(tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING ) {
98                       deliveryPendingList.remove(i);
99                    }
100                    PendingIntent intent = tracker.mDeliveryIntent;
101                    Intent fillIn = new Intent();
102                    fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString));
103                    fillIn.putExtra("format", SmsConstants.FORMAT_3GPP);
104                    try {
105                        intent.send(mContext, Activity.RESULT_OK, fillIn);
106                    } catch (CanceledException ex) {}
107
108                    // Only expect to see one tracker matching this messageref
109                    break;
110                }
111            }
112        }
113        mCi.acknowledgeLastIncomingGsmSms(true, Intents.RESULT_SMS_HANDLED, null);
114    }
115
116    /** {@inheritDoc} */
117    @Override
118    protected void sendData(String destAddr, String scAddr, int destPort,
119            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
120        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
121                scAddr, destAddr, destPort, data, (deliveryIntent != null));
122        if (pdu != null) {
123            sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent,
124                    destAddr);
125        } else {
126            Rlog.e(TAG, "GsmSMSDispatcher.sendData(): getSubmitPdu() returned null");
127        }
128    }
129
130    /** {@inheritDoc} */
131    @Override
132    protected void sendText(String destAddr, String scAddr, String text,
133            PendingIntent sentIntent, PendingIntent deliveryIntent) {
134        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
135                scAddr, destAddr, text, (deliveryIntent != null));
136        if (pdu != null) {
137            sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent,
138                    destAddr);
139        } else {
140            Rlog.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");
141        }
142    }
143
144    /** {@inheritDoc} */
145    @Override
146    protected GsmAlphabet.TextEncodingDetails calculateLength(CharSequence messageBody,
147            boolean use7bitOnly) {
148        return SmsMessage.calculateLength(messageBody, use7bitOnly);
149    }
150
151    /** {@inheritDoc} */
152    @Override
153    protected void sendNewSubmitPdu(String destinationAddress, String scAddress,
154            String message, SmsHeader smsHeader, int encoding,
155            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) {
156        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
157                message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
158                encoding, smsHeader.languageTable, smsHeader.languageShiftTable);
159        if (pdu != null) {
160            sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent,
161                    destinationAddress);
162        } else {
163            Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null");
164        }
165    }
166
167    /** {@inheritDoc} */
168    @Override
169    protected void sendSms(SmsTracker tracker) {
170        HashMap<String, Object> map = tracker.mData;
171
172        byte smsc[] = (byte[]) map.get("smsc");
173        byte pdu[] = (byte[]) map.get("pdu");
174
175        Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
176
177        if (tracker.mRetryCount > 0) {
178            Rlog.d(TAG, "sendSms: "
179                    + " mRetryCount=" + tracker.mRetryCount
180                    + " mMessageRef=" + tracker.mMessageRef
181                    + " SS=" + mPhone.getServiceState().getState());
182
183            // per TS 23.040 Section 9.2.3.6:  If TP-MTI SMS-SUBMIT (0x01) type
184            //   TP-RD (bit 2) is 1 for retry
185            //   and TP-MR is set to previously failed sms TP-MR
186            if (((0x01 & pdu[0]) == 0x01)) {
187                pdu[0] |= 0x04; // TP-RD
188                pdu[1] = (byte) tracker.mMessageRef; // TP-MR
189            }
190        }
191        mCi.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply);
192    }
193}
194