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 
17 package com.android.internal.telephony;
18 
19 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
20 import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE;
21 import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY;
22 
23 import android.app.Activity;
24 import android.app.PendingIntent;
25 import android.app.PendingIntent.CanceledException;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.net.Uri;
31 import android.os.AsyncResult;
32 import android.os.Handler;
33 import android.os.Message;
34 import android.os.UserManager;
35 import android.provider.Telephony.Sms;
36 import android.provider.Telephony.Sms.Intents;
37 import android.telephony.ServiceState;
38 import android.telephony.SmsManager;
39 import android.telephony.SmsMessage;
40 
41 import com.android.ims.ImsManager;
42 import com.android.internal.annotations.VisibleForTesting;
43 import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
44 import com.android.internal.telephony.cdma.CdmaSMSDispatcher;
45 import com.android.internal.telephony.gsm.GsmInboundSmsHandler;
46 import com.android.internal.telephony.gsm.GsmSMSDispatcher;
47 import com.android.telephony.Rlog;
48 
49 import java.io.FileDescriptor;
50 import java.io.PrintWriter;
51 import java.util.ArrayList;
52 import java.util.HashMap;
53 
54 /**
55  *
56  */
57 public class SmsDispatchersController extends Handler {
58     private static final String TAG = "SmsDispatchersController";
59     private static final boolean VDBG = false; // STOPSHIP if true
60 
61     /** Radio is ON */
62     private static final int EVENT_RADIO_ON = 11;
63 
64     /** IMS registration/SMS format changed */
65     private static final int EVENT_IMS_STATE_CHANGED = 12;
66 
67     /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */
68     private static final int EVENT_IMS_STATE_DONE = 13;
69 
70     /** Service state changed */
71     private static final int EVENT_SERVICE_STATE_CHANGED = 14;
72 
73     /** Purge old message segments */
74     private static final int EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY = 15;
75 
76     /** User unlocked the device */
77     private static final int EVENT_USER_UNLOCKED = 16;
78 
79     /** InboundSmsHandler exited WaitingState */
80     protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17;
81 
82     /** Delete any partial message segments after being IN_SERVICE for 1 day. */
83     private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24;
84     /** Constant for invalid time */
85     private static final long INVALID_TIME = -1;
86     /** Time at which last IN_SERVICE event was received */
87     private long mLastInServiceTime = INVALID_TIME;
88     /** Current IN_SERVICE duration */
89     private long mCurrentWaitElapsedDuration = 0;
90     /** Time at which the current PARTIAL_SEGMENT_WAIT_DURATION timer was started */
91     private long mCurrentWaitStartTime = INVALID_TIME;
92 
93     private SMSDispatcher mCdmaDispatcher;
94     private SMSDispatcher mGsmDispatcher;
95     private ImsSmsDispatcher mImsSmsDispatcher;
96 
97     private GsmInboundSmsHandler mGsmInboundSmsHandler;
98     private CdmaInboundSmsHandler mCdmaInboundSmsHandler;
99 
100     private Phone mPhone;
101     /** Outgoing message counter. Shared by all dispatchers. */
102     private final SmsUsageMonitor mUsageMonitor;
103     private final CommandsInterface mCi;
104     private final Context mContext;
105 
106     /** true if IMS is registered and sms is supported, false otherwise.*/
107     private boolean mIms = false;
108     private String mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN;
109 
110     /** 3GPP format sent messages awaiting a delivery status report. */
111     private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP = new HashMap<>();
112 
113     /** 3GPP2 format sent messages awaiting a delivery status report. */
114     private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP2 =
115             new HashMap<>();
116 
117     /**
118      * Puts a delivery pending tracker to the map based on the format.
119      *
120      * @param tracker the tracker awaiting a delivery status report.
121      */
putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker)122     public void putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker) {
123         if (isCdmaFormat(tracker.mFormat)) {
124             mDeliveryPendingMapFor3GPP2.put(tracker.mMessageRef, tracker);
125         } else {
126             mDeliveryPendingMapFor3GPP.put(tracker.mMessageRef, tracker);
127         }
128     }
129 
SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor)130     public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
131             SmsUsageMonitor usageMonitor) {
132         Rlog.d(TAG, "SmsDispatchersController created");
133 
134         mContext = phone.getContext();
135         mUsageMonitor = usageMonitor;
136         mCi = phone.mCi;
137         mPhone = phone;
138 
139         // Create dispatchers, inbound SMS handlers and
140         // broadcast undelivered messages in raw table.
141         mImsSmsDispatcher = new ImsSmsDispatcher(phone, this, ImsManager::getConnector);
142         mCdmaDispatcher = new CdmaSMSDispatcher(phone, this);
143         mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(),
144                 storageMonitor, phone);
145         mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(),
146                 storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher);
147         mGsmDispatcher = new GsmSMSDispatcher(phone, this, mGsmInboundSmsHandler);
148         SmsBroadcastUndelivered.initialize(phone.getContext(),
149                 mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
150         InboundSmsHandler.registerNewMessageNotificationActionHandler(phone.getContext());
151 
152         mCi.registerForOn(this, EVENT_RADIO_ON, null);
153         mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
154 
155         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
156         if (userManager.isUserUnlocked()) {
157             if (VDBG) {
158                 logd("SmsDispatchersController: user unlocked; registering for service"
159                         + "state changed");
160             }
161             mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
162             resetPartialSegmentWaitTimer();
163         } else {
164             if (VDBG) {
165                 logd("SmsDispatchersController: user locked; waiting for USER_UNLOCKED");
166             }
167             IntentFilter userFilter = new IntentFilter();
168             userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
169             mContext.registerReceiver(mBroadcastReceiver, userFilter);
170         }
171     }
172 
173     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
174         @Override
175         public void onReceive(final Context context, Intent intent) {
176             Rlog.d(TAG, "Received broadcast " + intent.getAction());
177             if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
178                 sendMessage(obtainMessage(EVENT_USER_UNLOCKED));
179             }
180         }
181     };
182 
dispose()183     public void dispose() {
184         mCi.unregisterForOn(this);
185         mCi.unregisterForImsNetworkStateChanged(this);
186         mPhone.unregisterForServiceStateChanged(this);
187         mGsmDispatcher.dispose();
188         mCdmaDispatcher.dispose();
189         mGsmInboundSmsHandler.dispose();
190         mCdmaInboundSmsHandler.dispose();
191     }
192 
193     /**
194      * Handles events coming from the phone stack. Overridden from handler.
195      *
196      * @param msg the message to handle
197      */
198     @Override
handleMessage(Message msg)199     public void handleMessage(Message msg) {
200         AsyncResult ar;
201 
202         switch (msg.what) {
203             case EVENT_RADIO_ON:
204             case EVENT_IMS_STATE_CHANGED: // received unsol
205                 mCi.getImsRegistrationState(this.obtainMessage(EVENT_IMS_STATE_DONE));
206                 break;
207 
208             case EVENT_IMS_STATE_DONE:
209                 ar = (AsyncResult) msg.obj;
210 
211                 if (ar.exception == null) {
212                     updateImsInfo(ar);
213                 } else {
214                     Rlog.e(TAG, "IMS State query failed with exp "
215                             + ar.exception);
216                 }
217                 break;
218 
219             case EVENT_SERVICE_STATE_CHANGED:
220             case EVENT_SMS_HANDLER_EXITING_WAITING_STATE:
221                 reevaluateTimerStatus();
222                 break;
223 
224             case EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY:
225                 handlePartialSegmentTimerExpiry((Long) msg.obj);
226                 break;
227 
228             case EVENT_USER_UNLOCKED:
229                 if (VDBG) {
230                     logd("handleMessage: EVENT_USER_UNLOCKED");
231                 }
232                 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
233                 resetPartialSegmentWaitTimer();
234                 break;
235 
236             default:
237                 if (isCdmaMo()) {
238                     mCdmaDispatcher.handleMessage(msg);
239                 } else {
240                     mGsmDispatcher.handleMessage(msg);
241                 }
242         }
243     }
244 
reevaluateTimerStatus()245     private void reevaluateTimerStatus() {
246         long currentTime = System.currentTimeMillis();
247 
248         // Remove unhandled timer expiry message. A new message will be posted if needed.
249         removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY);
250         // Update timer duration elapsed time (add time since last IN_SERVICE to now).
251         // This is needed for IN_SERVICE as well as OUT_OF_SERVICE because same events can be
252         // received back to back
253         if (mLastInServiceTime != INVALID_TIME) {
254             mCurrentWaitElapsedDuration += (currentTime - mLastInServiceTime);
255         }
256 
257         if (VDBG) {
258             logd("reevaluateTimerStatus: currentTime: " + currentTime
259                     + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration);
260         }
261 
262         if (mCurrentWaitElapsedDuration > PARTIAL_SEGMENT_WAIT_DURATION) {
263             // handle this event as timer expiry
264             handlePartialSegmentTimerExpiry(mCurrentWaitStartTime);
265         } else {
266             if (isInService()) {
267                 handleInService(currentTime);
268             } else {
269                 handleOutOfService(currentTime);
270             }
271         }
272     }
273 
handleInService(long currentTime)274     private void handleInService(long currentTime) {
275         if (VDBG) {
276             logd("handleInService: timer expiry in "
277                     + (PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration) + "ms");
278         }
279 
280         // initialize mCurrentWaitStartTime if needed
281         if (mCurrentWaitStartTime == INVALID_TIME) mCurrentWaitStartTime = currentTime;
282 
283         // Post a message for timer expiry time. mCurrentWaitElapsedDuration is the duration already
284         // elapsed from the timer.
285         sendMessageDelayed(
286                 obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime),
287                 PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration);
288 
289         // update mLastInServiceTime as the current time
290         mLastInServiceTime = currentTime;
291     }
292 
handleOutOfService(long currentTime)293     private void handleOutOfService(long currentTime) {
294         if (VDBG) {
295             logd("handleOutOfService: currentTime: " + currentTime
296                     + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration);
297         }
298 
299         // mLastInServiceTime is not relevant now since state is OUT_OF_SERVICE; set it to INVALID
300         mLastInServiceTime = INVALID_TIME;
301     }
302 
handlePartialSegmentTimerExpiry(long waitTimerStart)303     private void handlePartialSegmentTimerExpiry(long waitTimerStart) {
304         if (mGsmInboundSmsHandler.getCurrentState().getName().equals("WaitingState")
305                 || mCdmaInboundSmsHandler.getCurrentState().getName().equals("WaitingState")) {
306             logd("handlePartialSegmentTimerExpiry: ignoring timer expiry as InboundSmsHandler is"
307                     + " in WaitingState");
308             return;
309         }
310 
311         if (VDBG) {
312             logd("handlePartialSegmentTimerExpiry: calling scanRawTable()");
313         }
314         // Timer expired. This indicates that device has been in service for
315         // PARTIAL_SEGMENT_WAIT_DURATION since waitTimerStart. Delete orphaned message segments
316         // older than waitTimerStart.
317         SmsBroadcastUndelivered.scanRawTable(mContext, waitTimerStart);
318         if (VDBG) {
319             logd("handlePartialSegmentTimerExpiry: scanRawTable() done");
320         }
321 
322         resetPartialSegmentWaitTimer();
323     }
324 
resetPartialSegmentWaitTimer()325     private void resetPartialSegmentWaitTimer() {
326         long currentTime = System.currentTimeMillis();
327 
328         removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY);
329         if (isInService()) {
330             if (VDBG) {
331                 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime
332                         + " IN_SERVICE");
333             }
334             mCurrentWaitStartTime = currentTime;
335             mLastInServiceTime = currentTime;
336             sendMessageDelayed(
337                     obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime),
338                     PARTIAL_SEGMENT_WAIT_DURATION);
339         } else {
340             if (VDBG) {
341                 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime
342                         + " not IN_SERVICE");
343             }
344             mCurrentWaitStartTime = INVALID_TIME;
345             mLastInServiceTime = INVALID_TIME;
346         }
347 
348         mCurrentWaitElapsedDuration = 0;
349     }
350 
isInService()351     private boolean isInService() {
352         ServiceState serviceState = mPhone.getServiceState();
353         return serviceState != null && serviceState.getState() == ServiceState.STATE_IN_SERVICE;
354     }
355 
setImsSmsFormat(int format)356     private void setImsSmsFormat(int format) {
357         switch (format) {
358             case PhoneConstants.PHONE_TYPE_GSM:
359                 mImsSmsFormat = SmsConstants.FORMAT_3GPP;
360                 break;
361             case PhoneConstants.PHONE_TYPE_CDMA:
362                 mImsSmsFormat = SmsConstants.FORMAT_3GPP2;
363                 break;
364             default:
365                 mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN;
366                 break;
367         }
368     }
369 
updateImsInfo(AsyncResult ar)370     private void updateImsInfo(AsyncResult ar) {
371         int[] responseArray = (int[]) ar.result;
372         setImsSmsFormat(responseArray[1]);
373         mIms = responseArray[0] == 1 && !SmsConstants.FORMAT_UNKNOWN.equals(mImsSmsFormat);
374         Rlog.d(TAG, "IMS registration state: " + mIms + " format: " + mImsSmsFormat);
375     }
376 
377     /**
378      * Inject an SMS PDU into the android platform only if it is class 1.
379      *
380      * @param pdu is the byte array of pdu to be injected into android telephony layer
381      * @param format is the format of SMS pdu (3gpp or 3gpp2)
382      * @param callback if not NULL this callback is triggered when the message is successfully
383      *                 received by the android telephony layer. This callback is triggered at
384      *                 the same time an SMS received from radio is responded back.
385      */
386     @VisibleForTesting
injectSmsPdu(byte[] pdu, String format, boolean isOverIms, SmsInjectionCallback callback)387     public void injectSmsPdu(byte[] pdu, String format, boolean isOverIms,
388             SmsInjectionCallback callback) {
389         // TODO We need to decide whether we should allow injecting GSM(3gpp)
390         // SMS pdus when the phone is camping on CDMA(3gpp2) network and vice versa.
391         android.telephony.SmsMessage msg =
392                 android.telephony.SmsMessage.createFromPdu(pdu, format);
393         injectSmsPdu(msg, format, callback, false /* ignoreClass */, isOverIms);
394     }
395 
396     /**
397      * Inject an SMS PDU into the android platform.
398      *
399      * @param msg is the {@link SmsMessage} to be injected into android telephony layer
400      * @param format is the format of SMS pdu (3gpp or 3gpp2)
401      * @param callback if not NULL this callback is triggered when the message is successfully
402      *                 received by the android telephony layer. This callback is triggered at
403      *                 the same time an SMS received from radio is responded back.
404      * @param ignoreClass if set to false, this method will inject class 1 sms only.
405      */
406     @VisibleForTesting
injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, boolean ignoreClass, boolean isOverIms)407     public void injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback,
408             boolean ignoreClass, boolean isOverIms) {
409         Rlog.d(TAG, "SmsDispatchersController:injectSmsPdu");
410         try {
411             if (msg == null) {
412                 Rlog.e(TAG, "injectSmsPdu: createFromPdu returned null");
413                 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR);
414                 return;
415             }
416 
417             if (!ignoreClass
418                     && msg.getMessageClass() != android.telephony.SmsMessage.MessageClass.CLASS_1) {
419                 Rlog.e(TAG, "injectSmsPdu: not class 1");
420                 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR);
421                 return;
422             }
423 
424             AsyncResult ar = new AsyncResult(callback, msg, null);
425 
426             if (format.equals(SmsConstants.FORMAT_3GPP)) {
427                 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg
428                         + ", format=" + format + "to mGsmInboundSmsHandler");
429                 mGsmInboundSmsHandler.sendMessage(
430                         InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, 0, ar);
431             } else if (format.equals(SmsConstants.FORMAT_3GPP2)) {
432                 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg
433                         + ", format=" + format + "to mCdmaInboundSmsHandler");
434                 mCdmaInboundSmsHandler.sendMessage(
435                         InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, 0, ar);
436             } else {
437                 // Invalid pdu format.
438                 Rlog.e(TAG, "Invalid pdu format: " + format);
439                 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR);
440             }
441         } catch (Exception e) {
442             Rlog.e(TAG, "injectSmsPdu failed: ", e);
443             callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR);
444         }
445     }
446 
447     /**
448      * Retry the message along to the radio.
449      *
450      * @param tracker holds the SMS message to send
451      */
sendRetrySms(SMSDispatcher.SmsTracker tracker)452     public void sendRetrySms(SMSDispatcher.SmsTracker tracker) {
453         String oldFormat = tracker.mFormat;
454         boolean retryUsingImsService = false;
455 
456         if (!tracker.mUsesImsServiceForIms && mImsSmsDispatcher.isAvailable()) {
457             // If this tracker has not been handled by ImsSmsDispatcher yet and IMS Service is
458             // available now, retry this failed tracker using IMS Service.
459             retryUsingImsService = true;
460         }
461 
462         // If retryUsingImsService is true, newFormat will be IMS SMS format. Otherwise, newFormat
463         // will be based on voice technology.
464         String newFormat =
465                 retryUsingImsService
466                         ? mImsSmsDispatcher.getFormat()
467                         : (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType())
468                                 ? mCdmaDispatcher.getFormat()
469                                 : mGsmDispatcher.getFormat();
470 
471         Rlog.d(TAG, "old format(" + oldFormat + ") ==> new format (" + newFormat + ")");
472         if (!oldFormat.equals(newFormat)) {
473             // format didn't match, need to re-encode.
474             HashMap map = tracker.getData();
475 
476             // to re-encode, fields needed are: scAddr, destAddr and text if originally sent as
477             // sendText or data and destPort if originally sent as sendData.
478             if (!(map.containsKey("scAddr") && map.containsKey("destAddr")
479                     && (map.containsKey("text")
480                     || (map.containsKey("data") && map.containsKey("destPort"))))) {
481                 // should never come here...
482                 Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!");
483                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
484                 return;
485             }
486             String scAddr = (String) map.get("scAddr");
487             String destAddr = (String) map.get("destAddr");
488             if (destAddr == null) {
489                 Rlog.e(TAG, "sendRetrySms failed due to null destAddr");
490                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
491                 return;
492             }
493 
494             SmsMessageBase.SubmitPduBase pdu = null;
495             // figure out from tracker if this was sendText/Data
496             if (map.containsKey("text")) {
497                 String text = (String) map.get("text");
498                 Rlog.d(TAG, "sms failed was text with length: "
499                         + (text == null ? null : text.length()));
500 
501                 if (isCdmaFormat(newFormat)) {
502                     pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
503                             scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
504                 } else {
505                     pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
506                             scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
507                 }
508             } else if (map.containsKey("data")) {
509                 byte[] data = (byte[]) map.get("data");
510                 Integer destPort = (Integer) map.get("destPort");
511                 Rlog.d(TAG, "sms failed was data with length: "
512                         + (data == null ? null : data.length));
513 
514                 if (isCdmaFormat(newFormat)) {
515                     pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
516                             scAddr, destAddr, destPort.intValue(), data,
517                             (tracker.mDeliveryIntent != null));
518                 } else {
519                     pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
520                             scAddr, destAddr, destPort.intValue(), data,
521                             (tracker.mDeliveryIntent != null));
522                 }
523             }
524 
525             if (pdu == null) {
526                 Rlog.e(TAG, String.format("sendRetrySms failed to encode message."
527                         + "scAddr: %s, "
528                         + "destPort: %s", scAddr, map.get("destPort")));
529                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
530                 return;
531             }
532             // replace old smsc and pdu with newly encoded ones
533             map.put("smsc", pdu.encodedScAddress);
534             map.put("pdu", pdu.encodedMessage);
535             tracker.mFormat = newFormat;
536         }
537 
538         SMSDispatcher dispatcher =
539                 retryUsingImsService
540                         ? mImsSmsDispatcher
541                         : (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher;
542 
543         dispatcher.sendSms(tracker);
544     }
545 
546     /**
547      * SMS over IMS is supported if IMS is registered and SMS is supported on IMS.
548      *
549      * @return true if SMS over IMS is supported via an IMS Service or mIms is true for the older
550      *         implementation. Otherwise, false.
551      */
isIms()552     public boolean isIms() {
553         return mImsSmsDispatcher.isAvailable() ? true : mIms;
554     }
555 
556     /**
557      * Gets SMS format supported on IMS.
558      *
559      * @return the SMS format from an IMS Service if available. Otherwise, mImsSmsFormat for the
560      *         older implementation.
561      */
getImsSmsFormat()562     public String getImsSmsFormat() {
563         return mImsSmsDispatcher.isAvailable() ? mImsSmsDispatcher.getFormat() : mImsSmsFormat;
564     }
565 
566     /**
567      * Determines whether or not to use CDMA format for MO SMS.
568      * If SMS over IMS is supported, then format is based on IMS SMS format,
569      * otherwise format is based on current phone type.
570      *
571      * @return true if Cdma format should be used for MO SMS, false otherwise.
572      */
isCdmaMo()573     protected boolean isCdmaMo() {
574         if (!isIms()) {
575             // IMS is not registered, use Voice technology to determine SMS format.
576             return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType());
577         }
578         // IMS is registered with SMS support
579         return isCdmaFormat(getImsSmsFormat());
580     }
581 
582     /**
583      * Determines whether or not format given is CDMA format.
584      *
585      * @param format
586      * @return true if format given is CDMA format, false otherwise.
587      */
isCdmaFormat(String format)588     public boolean isCdmaFormat(String format) {
589         return (mCdmaDispatcher.getFormat().equals(format));
590     }
591 
592     /**
593      * Send a data based SMS to a specific application port.
594      *
595      * @param callingPackage the package name of the calling app
596      * @param destAddr the address to send the message to
597      * @param scAddr is the service center address or null to use
598      *  the current default SMSC
599      * @param destPort the port to deliver the message to
600      * @param data the body of the message to send
601      * @param sentIntent if not NULL this <code>PendingIntent</code> is
602      *  broadcast when the message is successfully sent, or failed.
603      *  The result code will be <code>Activity.RESULT_OK<code> for success,
604      *  or one of these errors:<br>
605      *  <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br>
606      *  <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br>
607      *  <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br>
608      *  <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br>
609      *  <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br>
610      *  <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
611      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
612      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
613      *  <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br>
614      *  <code>SmsManager.RESULT_NETWORK_REJECT</code><br>
615      *  <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br>
616      *  <code>SmsManager.RESULT_INVALID_STATE</code><br>
617      *  <code>SmsManager.RESULT_NO_MEMORY</code><br>
618      *  <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br>
619      *  <code>SmsManager.RESULT_SYSTEM_ERROR</code><br>
620      *  <code>SmsManager.RESULT_MODEM_ERROR</code><br>
621      *  <code>SmsManager.RESULT_NETWORK_ERROR</code><br>
622      *  <code>SmsManager.RESULT_ENCODING_ERROR</code><br>
623      *  <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br>
624      *  <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br>
625      *  <code>SmsManager.RESULT_INTERNAL_ERROR</code><br>
626      *  <code>SmsManager.RESULT_NO_RESOURCES</code><br>
627      *  <code>SmsManager.RESULT_CANCELLED</code><br>
628      *  <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br>
629      *  <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br>
630      *  <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
631      *  <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br>
632      *  <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
633      *  <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
634      *  <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br>
635      *  <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br>
636      *  <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br>
637      *  <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
638      *  <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
639      *  <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br>
640      *  <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br>
641      *  <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br>
642      *  <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br>
643      *  <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
644      *  <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br>
645      *  <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br>
646      *  <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br>
647      *  <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
648      *  <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br>
649      *  <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br>
650      *  <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br>
651      *  <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
652      *  <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br>
653      *  <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br>
654      *  <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
655      *  <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br>
656      *  <code>SmsManager.RESULT_RIL_CANCELLED</code><br>
657      *  <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br>
658      *  <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br>
659      *  <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br>
660      *  <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br>
661      *  For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
662      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
663      *  value, generally only useful for troubleshooting.<br>
664      *  The per-application based SMS control checks sentIntent. If sentIntent
665      *  is NULL the caller will be checked against all unknown applications,
666      *  which cause smaller number of SMS to be sent in checking period.
667      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
668      *  broadcast when the message is delivered to the recipient.  The
669      *  raw pdu of the status report is in the extended data ("pdu").
670      */
sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)671     protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort,
672             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) {
673         if (mImsSmsDispatcher.isAvailable()) {
674             mImsSmsDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
675                     deliveryIntent, isForVvm);
676         } else if (isCdmaMo()) {
677             mCdmaDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
678                     deliveryIntent, isForVvm);
679         } else {
680             mGsmDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
681                     deliveryIntent, isForVvm);
682         }
683     }
684 
685     /**
686      * Send a text based SMS.
687      *
688      * @param destAddr the address to send the message to
689      * @param scAddr is the service center address or null to use
690      *  the current default SMSC
691      * @param text the body of the message to send
692      * @param sentIntent if not NULL this <code>PendingIntent</code> is
693      *  broadcast when the message is successfully sent, or failed.
694      *  The result code will be <code>Activity.RESULT_OK<code> for success,
695      *  or one of these errors:<br>
696      *  <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br>
697      *  <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br>
698      *  <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br>
699      *  <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br>
700      *  <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br>
701      *  <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
702      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
703      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
704      *  <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br>
705      *  <code>SmsManager.RESULT_NETWORK_REJECT</code><br>
706      *  <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br>
707      *  <code>SmsManager.RESULT_INVALID_STATE</code><br>
708      *  <code>SmsManager.RESULT_NO_MEMORY</code><br>
709      *  <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br>
710      *  <code>SmsManager.RESULT_SYSTEM_ERROR</code><br>
711      *  <code>SmsManager.RESULT_MODEM_ERROR</code><br>
712      *  <code>SmsManager.RESULT_NETWORK_ERROR</code><br>
713      *  <code>SmsManager.RESULT_ENCODING_ERROR</code><br>
714      *  <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br>
715      *  <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br>
716      *  <code>SmsManager.RESULT_INTERNAL_ERROR</code><br>
717      *  <code>SmsManager.RESULT_NO_RESOURCES</code><br>
718      *  <code>SmsManager.RESULT_CANCELLED</code><br>
719      *  <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br>
720      *  <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br>
721      *  <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
722      *  <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br>
723      *  <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
724      *  <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
725      *  <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br>
726      *  <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br>
727      *  <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br>
728      *  <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
729      *  <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
730      *  <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br>
731      *  <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br>
732      *  <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br>
733      *  <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br>
734      *  <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
735      *  <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br>
736      *  <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br>
737      *  <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br>
738      *  <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
739      *  <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br>
740      *  <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br>
741      *  <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br>
742      *  <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
743      *  <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br>
744      *  <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br>
745      *  <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
746      *  <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br>
747      *  <code>SmsManager.RESULT_RIL_CANCELLED</code><br>
748      *  <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br>
749      *  <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br>
750      *  <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br>
751      *  <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br>
752      *  For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
753      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
754      *  value, generally only useful for troubleshooting.<br>
755      *  The per-application based SMS control checks sentIntent. If sentIntent
756      *  is NULL the caller will be checked against all unknown applications,
757      *  which cause smaller number of SMS to be sent in checking period.
758      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
759      *  broadcast when the message is delivered to the recipient.  The
760      * @param messageUri optional URI of the message if it is already stored in the system
761      * @param callingPkg the calling package name
762      * @param persistMessage whether to save the sent message into SMS DB for a
763      *  non-default SMS app.
764      * @param priority Priority level of the message
765      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
766      *  ---------------------------------
767      *  PRIORITY      | Level of Priority
768      *  ---------------------------------
769      *      '00'      |     Normal
770      *      '01'      |     Interactive
771      *      '10'      |     Urgent
772      *      '11'      |     Emergency
773      *  ----------------------------------
774      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
775      * @param expectMore is a boolean to indicate the sending messages through same link or not.
776      * @param validityPeriod Validity Period of the message in mins.
777      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
778      *  Validity Period(Minimum) -> 5 mins
779      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
780      *  Any Other values included Negative considered as Invalid Validity Period of the message.
781      */
sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId)782     public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent,
783             PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage,
784             int priority, boolean expectMore, int validityPeriod, boolean isForVvm,
785             long messageId) {
786         if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport(destAddr)) {
787             mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
788                     messageUri, callingPkg, persistMessage, priority, false /*expectMore*/,
789                     validityPeriod, isForVvm, messageId);
790         } else {
791             if (isCdmaMo()) {
792                 mCdmaDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
793                         messageUri, callingPkg, persistMessage, priority, expectMore,
794                         validityPeriod, isForVvm, messageId);
795             } else {
796                 mGsmDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
797                         messageUri, callingPkg, persistMessage, priority, expectMore,
798                         validityPeriod, isForVvm, messageId);
799             }
800         }
801     }
802 
803     /**
804      * Send a multi-part text based SMS.
805      *
806      * @param destAddr the address to send the message to
807      * @param scAddr is the service center address or null to use
808      *  the current default SMSC
809      * @param parts an <code>ArrayList</code> of strings that, in order,
810      *  comprise the original message
811      * @param sentIntents if not null, an <code>ArrayList</code> of
812      *  <code>PendingIntent</code>s (one for each message part) that is
813      *  broadcast when the corresponding message part has been sent.
814      *  The result code will be <code>Activity.RESULT_OK<code> for success,
815      *  or one of these errors:<br>
816      *  <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br>
817      *  <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br>
818      *  <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br>
819      *  <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br>
820      *  <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br>
821      *  <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
822      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
823      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
824      *  <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br>
825      *  <code>SmsManager.RESULT_NETWORK_REJECT</code><br>
826      *  <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br>
827      *  <code>SmsManager.RESULT_INVALID_STATE</code><br>
828      *  <code>SmsManager.RESULT_NO_MEMORY</code><br>
829      *  <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br>
830      *  <code>SmsManager.RESULT_SYSTEM_ERROR</code><br>
831      *  <code>SmsManager.RESULT_MODEM_ERROR</code><br>
832      *  <code>SmsManager.RESULT_NETWORK_ERROR</code><br>
833      *  <code>SmsManager.RESULT_ENCODING_ERROR</code><br>
834      *  <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br>
835      *  <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br>
836      *  <code>SmsManager.RESULT_INTERNAL_ERROR</code><br>
837      *  <code>SmsManager.RESULT_NO_RESOURCES</code><br>
838      *  <code>SmsManager.RESULT_CANCELLED</code><br>
839      *  <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br>
840      *  <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br>
841      *  <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
842      *  <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br>
843      *  <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
844      *  <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
845      *  <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br>
846      *  <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br>
847      *  <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br>
848      *  <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
849      *  <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
850      *  <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br>
851      *  <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br>
852      *  <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br>
853      *  <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br>
854      *  <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
855      *  <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br>
856      *  <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br>
857      *  <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br>
858      *  <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
859      *  <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br>
860      *  <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br>
861      *  <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br>
862      *  <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
863      *  <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br>
864      *  <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br>
865      *  <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
866      *  <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br>
867      *  <code>SmsManager.RESULT_RIL_CANCELLED</code><br>
868      *  <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br>
869      *  <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br>
870      *  <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br>
871      *  <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br>
872      *  For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
873      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
874      *  value, generally only useful for troubleshooting.<br>
875      *  The per-application based SMS control checks sentIntent. If sentIntent
876      *  is NULL the caller will be checked against all unknown applications,
877      *  which cause smaller number of SMS to be sent in checking period.
878      * @param deliveryIntents if not null, an <code>ArrayList</code> of
879      *  <code>PendingIntent</code>s (one for each message part) that is
880      *  broadcast when the corresponding message part has been delivered
881      *  to the recipient.  The raw pdu of the status report is in the
882      * @param messageUri optional URI of the message if it is already stored in the system
883      * @param callingPkg the calling package name
884      * @param persistMessage whether to save the sent message into SMS DB for a
885      *  non-default SMS app.
886      * @param priority Priority level of the message
887      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
888      *  ---------------------------------
889      *  PRIORITY      | Level of Priority
890      *  ---------------------------------
891      *      '00'      |     Normal
892      *      '01'      |     Interactive
893      *      '10'      |     Urgent
894      *      '11'      |     Emergency
895      *  ----------------------------------
896      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
897      * @param expectMore is a boolean to indicate the sending messages through same link or not.
898      * @param validityPeriod Validity Period of the message in mins.
899      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
900      *  Validity Period(Minimum) -> 5 mins
901      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
902      *  Any Other values included Negative considered as Invalid Validity Period of the message.
903      * @param messageId An id that uniquely identifies the message requested to be sent.
904      *                 Used for logging and diagnostics purposes. The id may be 0.
905      *
906      */
sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId)907     protected void sendMultipartText(String destAddr, String scAddr,
908             ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
909             ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
910             boolean persistMessage, int priority, boolean expectMore, int validityPeriod,
911             long messageId) {
912         if (mImsSmsDispatcher.isAvailable()) {
913             mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
914                     deliveryIntents, messageUri, callingPkg, persistMessage, priority,
915                     false /*expectMore*/, validityPeriod, messageId);
916         } else {
917             if (isCdmaMo()) {
918                 mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
919                         deliveryIntents, messageUri, callingPkg, persistMessage, priority,
920                         expectMore, validityPeriod, messageId);
921             } else {
922                 mGsmDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
923                         deliveryIntents, messageUri, callingPkg, persistMessage, priority,
924                         expectMore, validityPeriod, messageId);
925             }
926         }
927     }
928 
929     /**
930      * Returns the premium SMS permission for the specified package. If the package has never
931      * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN}
932      * will be returned.
933      * @param packageName the name of the package to query permission
934      * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
935      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
936      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
937      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
938      */
getPremiumSmsPermission(String packageName)939     public int getPremiumSmsPermission(String packageName) {
940         return mUsageMonitor.getPremiumSmsPermission(packageName);
941     }
942 
943     /**
944      * Sets the premium SMS permission for the specified package and save the value asynchronously
945      * to persistent storage.
946      * @param packageName the name of the package to set permission
947      * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
948      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
949      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
950      */
setPremiumSmsPermission(String packageName, int permission)951     public void setPremiumSmsPermission(String packageName, int permission) {
952         mUsageMonitor.setPremiumSmsPermission(packageName, permission);
953     }
954 
getUsageMonitor()955     public SmsUsageMonitor getUsageMonitor() {
956         return mUsageMonitor;
957     }
958 
959     /**
960      * Handles the sms status report based on the format.
961      *
962      * @param format the format.
963      * @param pdu the pdu of the report.
964      */
handleSmsStatusReport(String format, byte[] pdu)965     public void handleSmsStatusReport(String format, byte[] pdu) {
966         int messageRef;
967         SMSDispatcher.SmsTracker tracker;
968         boolean handled = false;
969         if (isCdmaFormat(format)) {
970             com.android.internal.telephony.cdma.SmsMessage sms =
971                     com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
972             if (sms != null) {
973                 boolean foundIn3GPPMap = false;
974                 messageRef = sms.mMessageRef;
975                 tracker = mDeliveryPendingMapFor3GPP2.get(messageRef);
976                 if (tracker == null) {
977                     // A tracker for this 3GPP2 report may be in the 3GPP map instead if the
978                     // previously submitted SMS was 3GPP format.
979                     // (i.e. Some carriers require that devices receive 3GPP2 SMS also even if IMS
980                     // SMS format is 3GGP.)
981                     tracker = mDeliveryPendingMapFor3GPP.get(messageRef);
982                     if (tracker != null) {
983                         foundIn3GPPMap = true;
984                     }
985                 }
986                 if (tracker != null) {
987                     // The status is composed of an error class (bits 25-24) and a status code
988                     // (bits 23-16).
989                     int errorClass = (sms.getStatus() >> 24) & 0x03;
990                     if (errorClass != ERROR_TEMPORARY) {
991                         // Update the message status (COMPLETE or FAILED)
992                         tracker.updateSentMessageStatus(
993                                 mContext,
994                                 (errorClass == ERROR_NONE)
995                                         ? Sms.STATUS_COMPLETE
996                                         : Sms.STATUS_FAILED);
997                         // No longer need to be kept.
998                         if (foundIn3GPPMap) {
999                             mDeliveryPendingMapFor3GPP.remove(messageRef);
1000                         } else {
1001                             mDeliveryPendingMapFor3GPP2.remove(messageRef);
1002                         }
1003                     }
1004                     handled = triggerDeliveryIntent(tracker, format, pdu);
1005                 }
1006             }
1007         } else {
1008             com.android.internal.telephony.gsm.SmsMessage sms =
1009                     com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
1010             if (sms != null) {
1011                 messageRef = sms.mMessageRef;
1012                 tracker = mDeliveryPendingMapFor3GPP.get(messageRef);
1013                 if (tracker != null) {
1014                     int tpStatus = sms.getStatus();
1015                     if (tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING) {
1016                         // Update the message status (COMPLETE or FAILED)
1017                         tracker.updateSentMessageStatus(mContext, tpStatus);
1018                         // No longer need to be kept.
1019                         mDeliveryPendingMapFor3GPP.remove(messageRef);
1020                     }
1021                     handled = triggerDeliveryIntent(tracker, format, pdu);
1022                 }
1023             }
1024         }
1025 
1026         if (!handled) {
1027             Rlog.e(TAG, "handleSmsStatusReport: can not handle the status report!");
1028         }
1029     }
1030 
triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu)1031     private boolean triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format,
1032                                           byte[] pdu) {
1033         PendingIntent intent = tracker.mDeliveryIntent;
1034         Intent fillIn = new Intent();
1035         fillIn.putExtra("pdu", pdu);
1036         fillIn.putExtra("format", format);
1037         try {
1038             intent.send(mContext, Activity.RESULT_OK, fillIn);
1039             return true;
1040         } catch (CanceledException ex) {
1041             return false;
1042         }
1043     }
1044 
1045     /**
1046      * Get InboundSmsHandler for the phone.
1047      */
getInboundSmsHandler(boolean is3gpp2)1048     public InboundSmsHandler getInboundSmsHandler(boolean is3gpp2) {
1049         if (is3gpp2) return mCdmaInboundSmsHandler;
1050         else return mGsmInboundSmsHandler;
1051     }
1052 
1053     public interface SmsInjectionCallback {
onSmsInjectedResult(int result)1054         void onSmsInjectedResult(int result);
1055     }
1056 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1057     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1058         mGsmInboundSmsHandler.dump(fd, pw, args);
1059         mCdmaInboundSmsHandler.dump(fd, pw, args);
1060         mGsmDispatcher.dump(fd, pw, args);
1061         mCdmaDispatcher.dump(fd, pw, args);
1062         mImsSmsDispatcher.dump(fd, pw, args);
1063     }
1064 
logd(String msg)1065     private void logd(String msg) {
1066         Rlog.d(TAG, msg);
1067     }
1068 }
1069