ImsSMSDispatcher.java revision d2feaf918ab0c1173d4ada182532e48d0c0d3f77
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.internal.telephony;
19
20import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
21
22import java.util.ArrayList;
23import java.util.HashMap;
24
25import android.app.PendingIntent;
26import android.app.PendingIntent.CanceledException;
27import android.os.AsyncResult;
28import android.os.Message;
29import android.provider.Telephony.Sms.Intents;
30import android.telephony.Rlog;
31
32import com.android.internal.telephony.cdma.CdmaSMSDispatcher;
33import com.android.internal.telephony.gsm.GsmSMSDispatcher;
34import com.android.internal.telephony.InboundSmsHandler;
35import com.android.internal.telephony.gsm.GsmInboundSmsHandler;
36import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
37import com.android.internal.telephony.SmsBroadcastUndelivered;
38
39public final class ImsSMSDispatcher extends SMSDispatcher {
40    private static final String TAG = "RIL_ImsSms";
41
42    private SMSDispatcher mCdmaDispatcher;
43    private SMSDispatcher mGsmDispatcher;
44
45    GsmInboundSmsHandler mGsmInboundSmsHandler;
46    CdmaInboundSmsHandler mCdmaInboundSmsHandler;
47
48    /** true if IMS is registered and sms is supported, false otherwise.*/
49    private boolean mIms = false;
50    private String mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN;
51
52    public ImsSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
53            SmsUsageMonitor usageMonitor) {
54        super(phone, usageMonitor);
55        Rlog.d(TAG, "ImsSMSDispatcher created");
56
57        // Create dispatchers, inbound SMS handlers and broadcast
58        // undelivered messages in raw table.
59        mCdmaDispatcher = new CdmaSMSDispatcher(phone,
60                storageMonitor, usageMonitor, this);
61        mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(),
62                storageMonitor, phone);
63        mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(),
64                storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher);
65        mGsmDispatcher = new GsmSMSDispatcher(phone,
66                storageMonitor, usageMonitor, this, mGsmInboundSmsHandler);
67        Thread broadcastThread = new Thread(new SmsBroadcastUndelivered(phone.getContext(),
68                mGsmInboundSmsHandler, mCdmaInboundSmsHandler));
69        broadcastThread.start();
70
71        mCi.registerForOn(this, EVENT_RADIO_ON, null);
72        mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
73    }
74
75    /* Updates the phone object when there is a change */
76    @Override
77    protected void updatePhoneObject(PhoneBase phone) {
78        Rlog.d(TAG, "In IMS updatePhoneObject ");
79        super.updatePhoneObject(phone);
80        mCdmaDispatcher.updatePhoneObject(phone);
81        mGsmDispatcher.updatePhoneObject(phone);
82        mGsmInboundSmsHandler.updatePhoneObject(phone);
83        mCdmaInboundSmsHandler.updatePhoneObject(phone);
84    }
85
86    public void dispose() {
87        mCi.unregisterForOn(this);
88        mCi.unregisterForImsNetworkStateChanged(this);
89        mGsmDispatcher.dispose();
90        mCdmaDispatcher.dispose();
91        mGsmInboundSmsHandler.dispose();
92        mCdmaInboundSmsHandler.dispose();
93    }
94
95    /**
96     * Handles events coming from the phone stack. Overridden from handler.
97     *
98     * @param msg the message to handle
99     */
100    @Override
101    public void handleMessage(Message msg) {
102        AsyncResult ar;
103
104        switch (msg.what) {
105        case EVENT_RADIO_ON:
106        case EVENT_IMS_STATE_CHANGED: // received unsol
107            mCi.getImsRegistrationState(this.obtainMessage(EVENT_IMS_STATE_DONE));
108            break;
109
110        case EVENT_IMS_STATE_DONE:
111            ar = (AsyncResult) msg.obj;
112
113            if (ar.exception == null) {
114                updateImsInfo(ar);
115            } else {
116                Rlog.e(TAG, "IMS State query failed with exp "
117                        + ar.exception);
118            }
119            break;
120
121        default:
122            super.handleMessage(msg);
123        }
124    }
125
126    private void setImsSmsFormat(int format) {
127        // valid format?
128        switch (format) {
129            case PhoneConstants.PHONE_TYPE_GSM:
130                mImsSmsFormat = "3gpp";
131                break;
132            case PhoneConstants.PHONE_TYPE_CDMA:
133                mImsSmsFormat = "3gpp2";
134                break;
135            default:
136                mImsSmsFormat = "unknown";
137                break;
138        }
139    }
140
141    private void updateImsInfo(AsyncResult ar) {
142        int[] responseArray = (int[])ar.result;
143
144        mIms = false;
145        if (responseArray[0] == 1) {  // IMS is registered
146            Rlog.d(TAG, "IMS is registered!");
147            mIms = true;
148        } else {
149            Rlog.d(TAG, "IMS is NOT registered!");
150        }
151
152        setImsSmsFormat(responseArray[1]);
153
154        if (("unknown".equals(mImsSmsFormat))) {
155            Rlog.e(TAG, "IMS format was unknown!");
156            // failed to retrieve valid IMS SMS format info, set IMS to unregistered
157            mIms = false;
158        }
159    }
160
161    @Override
162    protected void sendData(String destAddr, String scAddr, int destPort,
163            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
164        if (isCdmaMo()) {
165            mCdmaDispatcher.sendData(destAddr, scAddr, destPort,
166                    data, sentIntent, deliveryIntent);
167        } else {
168            mGsmDispatcher.sendData(destAddr, scAddr, destPort,
169                    data, sentIntent, deliveryIntent);
170        }
171    }
172
173    @Override
174    protected void sendMultipartText(String destAddr, String scAddr,
175            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
176            ArrayList<PendingIntent> deliveryIntents) {
177        if (isCdmaMo()) {
178            mCdmaDispatcher.sendMultipartText(destAddr, scAddr,
179                    parts, sentIntents, deliveryIntents);
180        } else {
181            mGsmDispatcher.sendMultipartText(destAddr, scAddr,
182                    parts, sentIntents, deliveryIntents);
183        }
184    }
185
186    @Override
187    protected void sendSms(SmsTracker tracker) {
188        //  sendSms is a helper function to other send functions, sendText/Data...
189        //  it is not part of ISms.stub
190        Rlog.e(TAG, "sendSms should never be called from here!");
191    }
192
193    @Override
194    protected void sendText(String destAddr, String scAddr, String text,
195            PendingIntent sentIntent, PendingIntent deliveryIntent) {
196        Rlog.d(TAG, "sendText");
197        if (isCdmaMo()) {
198            mCdmaDispatcher.sendText(destAddr, scAddr,
199                    text, sentIntent, deliveryIntent);
200        } else {
201            mGsmDispatcher.sendText(destAddr, scAddr,
202                    text, sentIntent, deliveryIntent);
203        }
204    }
205
206    @Override
207    public void sendRetrySms(SmsTracker tracker) {
208        String oldFormat = tracker.mFormat;
209
210        // newFormat will be based on voice technology
211        String newFormat =
212            (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()) ?
213                    mCdmaDispatcher.getFormat() :
214                        mGsmDispatcher.getFormat();
215
216        // was previously sent sms format match with voice tech?
217        if (oldFormat.equals(newFormat)) {
218            if (isCdmaFormat(newFormat)) {
219                Rlog.d(TAG, "old format matched new format (cdma)");
220                mCdmaDispatcher.sendSms(tracker);
221                return;
222            } else {
223                Rlog.d(TAG, "old format matched new format (gsm)");
224                mGsmDispatcher.sendSms(tracker);
225                return;
226            }
227        }
228
229        // format didn't match, need to re-encode.
230        HashMap map = tracker.mData;
231
232        // to re-encode, fields needed are:  scAddr, destAddr, and
233        //   text if originally sent as sendText or
234        //   data and destPort if originally sent as sendData.
235        if (!( map.containsKey("scAddr") && map.containsKey("destAddr") &&
236               ( map.containsKey("text") ||
237                       (map.containsKey("data") && map.containsKey("destPort"))))) {
238            // should never come here...
239            Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!");
240            if (tracker.mSentIntent != null) {
241                int error = RESULT_ERROR_GENERIC_FAILURE;
242                // Done retrying; return an error to the app.
243                try {
244                    tracker.mSentIntent.send(mContext, error, null);
245                } catch (CanceledException ex) {}
246            }
247            return;
248        }
249        String scAddr = (String)map.get("scAddr");
250        String destAddr = (String)map.get("destAddr");
251
252        SmsMessageBase.SubmitPduBase pdu = null;
253        //    figure out from tracker if this was sendText/Data
254        if (map.containsKey("text")) {
255            Rlog.d(TAG, "sms failed was text");
256            String text = (String)map.get("text");
257
258            if (isCdmaFormat(newFormat)) {
259                Rlog.d(TAG, "old format (gsm) ==> new format (cdma)");
260                pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
261                        scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
262            } else {
263                Rlog.d(TAG, "old format (cdma) ==> new format (gsm)");
264                pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
265                        scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
266            }
267        } else if (map.containsKey("data")) {
268            Rlog.d(TAG, "sms failed was data");
269            byte[] data = (byte[])map.get("data");
270            Integer destPort = (Integer)map.get("destPort");
271
272            if (isCdmaFormat(newFormat)) {
273                Rlog.d(TAG, "old format (gsm) ==> new format (cdma)");
274                pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
275                            scAddr, destAddr, destPort.intValue(), data,
276                            (tracker.mDeliveryIntent != null));
277            } else {
278                Rlog.d(TAG, "old format (cdma) ==> new format (gsm)");
279                pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
280                            scAddr, destAddr, destPort.intValue(), data,
281                            (tracker.mDeliveryIntent != null));
282            }
283        }
284
285        // replace old smsc and pdu with newly encoded ones
286        map.put("smsc", pdu.encodedScAddress);
287        map.put("pdu", pdu.encodedMessage);
288
289        SMSDispatcher dispatcher = (isCdmaFormat(newFormat)) ?
290                mCdmaDispatcher : mGsmDispatcher;
291
292        tracker.mFormat = dispatcher.getFormat();
293        dispatcher.sendSms(tracker);
294    }
295
296    @Override
297    protected String getFormat() {
298        // this function should be defined in Gsm/CdmaDispatcher.
299        Rlog.e(TAG, "getFormat should never be called from here!");
300        return "unknown";
301    }
302
303    @Override
304    protected GsmAlphabet.TextEncodingDetails calculateLength(
305            CharSequence messageBody, boolean use7bitOnly) {
306        Rlog.e(TAG, "Error! Not implemented for IMS.");
307        return null;
308    }
309
310    @Override
311    protected void sendNewSubmitPdu(String destinationAddress, String scAddress, String message,
312            SmsHeader smsHeader, int format, PendingIntent sentIntent,
313            PendingIntent deliveryIntent, boolean lastPart) {
314        Rlog.e(TAG, "Error! Not implemented for IMS.");
315    }
316
317    @Override
318    public boolean isIms() {
319        return mIms;
320    }
321
322    @Override
323    public String getImsSmsFormat() {
324        return mImsSmsFormat;
325    }
326
327    /**
328     * Determines whether or not to use CDMA format for MO SMS.
329     * If SMS over IMS is supported, then format is based on IMS SMS format,
330     * otherwise format is based on current phone type.
331     *
332     * @return true if Cdma format should be used for MO SMS, false otherwise.
333     */
334    private boolean isCdmaMo() {
335        if (!isIms()) {
336            // IMS is not registered, use Voice technology to determine SMS format.
337            return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType());
338        }
339        // IMS is registered with SMS support
340        return isCdmaFormat(mImsSmsFormat);
341    }
342
343    /**
344     * Determines whether or not format given is CDMA format.
345     *
346     * @param format
347     * @return true if format given is CDMA format, false otherwise.
348     */
349    private boolean isCdmaFormat(String format) {
350        return (mCdmaDispatcher.getFormat().equals(format));
351    }
352}
353