• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.app.Activity;
26 import android.app.PendingIntent;
27 import android.app.PendingIntent.CanceledException;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.net.Uri;
33 import android.os.AsyncResult;
34 import android.os.Binder;
35 import android.os.Handler;
36 import android.os.Looper;
37 import android.os.Message;
38 import android.os.UserManager;
39 import android.provider.Telephony.Sms;
40 import android.provider.Telephony.Sms.Intents;
41 import android.telephony.Annotation.DisconnectCauses;
42 import android.telephony.DomainSelectionService;
43 import android.telephony.NetworkRegistrationInfo;
44 import android.telephony.ServiceState;
45 import android.telephony.SmsManager;
46 import android.telephony.SmsMessage;
47 import android.telephony.TelephonyManager;
48 import android.text.TextUtils;
49 
50 import com.android.ims.ImsManager;
51 import com.android.internal.annotations.VisibleForTesting;
52 import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
53 import com.android.internal.telephony.cdma.CdmaSMSDispatcher;
54 import com.android.internal.telephony.domainselection.DomainSelectionConnection;
55 import com.android.internal.telephony.domainselection.DomainSelectionResolver;
56 import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection;
57 import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection;
58 import com.android.internal.telephony.gsm.GsmInboundSmsHandler;
59 import com.android.internal.telephony.gsm.GsmSMSDispatcher;
60 import com.android.telephony.Rlog;
61 
62 import java.io.FileDescriptor;
63 import java.io.PrintWriter;
64 import java.util.ArrayList;
65 import java.util.HashMap;
66 import java.util.List;
67 import java.util.concurrent.CompletableFuture;
68 
69 /**
70  *
71  */
72 public class SmsDispatchersController extends Handler {
73     private static final String TAG = "SmsDispatchersController";
74     private static final boolean VDBG = false; // STOPSHIP if true
75 
76     /** Radio is ON */
77     private static final int EVENT_RADIO_ON = 11;
78 
79     /** IMS registration/SMS format changed */
80     private static final int EVENT_IMS_STATE_CHANGED = 12;
81 
82     /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */
83     private static final int EVENT_IMS_STATE_DONE = 13;
84 
85     /** Service state changed */
86     private static final int EVENT_SERVICE_STATE_CHANGED = 14;
87 
88     /** Purge old message segments */
89     private static final int EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY = 15;
90 
91     /** User unlocked the device */
92     private static final int EVENT_USER_UNLOCKED = 16;
93 
94     /** InboundSmsHandler exited WaitingState */
95     protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17;
96 
97     /** Delete any partial message segments after being IN_SERVICE for 1 day. */
98     private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24;
99     /** Constant for invalid time */
100     private static final long INVALID_TIME = -1;
101     /** Time at which last IN_SERVICE event was received */
102     private long mLastInServiceTime = INVALID_TIME;
103     /** Current IN_SERVICE duration */
104     private long mCurrentWaitElapsedDuration = 0;
105     /** Time at which the current PARTIAL_SEGMENT_WAIT_DURATION timer was started */
106     private long mCurrentWaitStartTime = INVALID_TIME;
107 
108     private SMSDispatcher mCdmaDispatcher;
109     private SMSDispatcher mGsmDispatcher;
110     private ImsSmsDispatcher mImsSmsDispatcher;
111 
112     private GsmInboundSmsHandler mGsmInboundSmsHandler;
113     private CdmaInboundSmsHandler mCdmaInboundSmsHandler;
114 
115     private Phone mPhone;
116     /** Outgoing message counter. Shared by all dispatchers. */
117     private final SmsUsageMonitor mUsageMonitor;
118     private final CommandsInterface mCi;
119     private final Context mContext;
120 
121     /** true if IMS is registered and sms is supported, false otherwise.*/
122     private boolean mIms = false;
123     private String mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN;
124 
125     /** 3GPP format sent messages awaiting a delivery status report. */
126     private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP = new HashMap<>();
127 
128     /** 3GPP2 format sent messages awaiting a delivery status report. */
129     private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP2 =
130             new HashMap<>();
131 
132     /**
133      * Testing interface for injecting mock DomainSelectionConnection and a flag to indicate
134      * whether the domain selection is supported.
135      */
136     @VisibleForTesting
137     public interface DomainSelectionResolverProxy {
138         /**
139          * Returns a {@link DomainSelectionConnection} created using the specified
140          * context and callback.
141          *
142          * @param phone The {@link Phone} instance.
143          * @param selectorType The domain selector type to identify the domain selection connection.
144          *                     A {@link DomainSelectionService#SELECTOR_TYPE_SMS} is used for SMS.
145          * @param isEmergency A flag to indicate whether this connection is
146          *                    for an emergency SMS or not.
147          */
getDomainSelectionConnection(Phone phone, @DomainSelectionService.SelectorType int selectorType, boolean isEmergency)148         @Nullable DomainSelectionConnection getDomainSelectionConnection(Phone phone,
149                 @DomainSelectionService.SelectorType int selectorType, boolean isEmergency);
150 
151         /**
152          * Checks if the device supports the domain selection service to route the call / SMS /
153          * supplementary services to the appropriate domain.
154          *
155          * @return {@code true} if the domain selection is supported on the device,
156          *         {@code false} otherwise.
157          */
isDomainSelectionSupported()158         boolean isDomainSelectionSupported();
159     }
160 
161     private DomainSelectionResolverProxy mDomainSelectionResolverProxy =
162             new DomainSelectionResolverProxy() {
163                 @Override
164                 @Nullable
165                 public DomainSelectionConnection getDomainSelectionConnection(Phone phone,
166                         @DomainSelectionService.SelectorType int selectorType,
167                         boolean isEmergency) {
168                     try {
169                         return DomainSelectionResolver.getInstance().getDomainSelectionConnection(
170                                 phone, selectorType, isEmergency);
171                     } catch (IllegalStateException e) {
172                         // In general, DomainSelectionResolver is always initialized by TeleService,
173                         // but if it's not initialized (like in unit tests),
174                         // it returns null to perform the legacy behavior in this case.
175                         return null;
176                     }
177                 }
178 
179                 @Override
180                 public boolean isDomainSelectionSupported() {
181                     return DomainSelectionResolver.getInstance().isDomainSelectionSupported();
182                 }
183             };
184 
185     /** Stores the sending SMS information for a pending request. */
186     private class PendingRequest {
187         public static final int TYPE_DATA = 1;
188         public static final int TYPE_TEXT = 2;
189         public static final int TYPE_MULTIPART_TEXT = 3;
190         public static final int TYPE_RETRY_SMS = 4;
191 
192         public final int type;
193         public final SMSDispatcher.SmsTracker tracker;
194         public final String callingPackage;
195         public final String destAddr;
196         public final String scAddr;
197         public final ArrayList<PendingIntent> sentIntents;
198         public final ArrayList<PendingIntent> deliveryIntents;
199         public final boolean isForVvm;
200         // sendData specific
201         public final byte[] data;
202         public final int destPort;
203         // sendText / sendMultipartText specific
204         public final ArrayList<String> texts;
205         public final Uri messageUri;
206         public final boolean persistMessage;
207         public final int priority;
208         public final boolean expectMore;
209         public final int validityPeriod;
210         public final long messageId;
211         public final boolean skipShortCodeCheck;
212 
PendingRequest(int type, SMSDispatcher.SmsTracker tracker, String callingPackage, String destAddr, String scAddr, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, boolean isForVvm, byte[] data, int destPort, ArrayList<String> texts, Uri messageUri, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId, boolean skipShortCodeCheck)213         PendingRequest(int type, SMSDispatcher.SmsTracker tracker, String callingPackage,
214                 String destAddr, String scAddr, ArrayList<PendingIntent> sentIntents,
215                 ArrayList<PendingIntent> deliveryIntents, boolean isForVvm, byte[] data,
216                 int destPort, ArrayList<String> texts, Uri messageUri, boolean persistMessage,
217                 int priority, boolean expectMore, int validityPeriod, long messageId,
218                 boolean skipShortCodeCheck) {
219             this.type = type;
220             this.tracker = tracker;
221             this.callingPackage = callingPackage;
222             this.destAddr = destAddr;
223             this.scAddr = scAddr;
224             this.sentIntents = sentIntents;
225             this.deliveryIntents = deliveryIntents;
226             this.isForVvm = isForVvm;
227 
228             this.data = data;
229             this.destPort = destPort;
230 
231             this.texts = texts;
232             this.messageUri = messageUri;
233             this.persistMessage = persistMessage;
234             this.priority = priority;
235             this.expectMore = expectMore;
236             this.validityPeriod = validityPeriod;
237             this.messageId = messageId;
238             this.skipShortCodeCheck = skipShortCodeCheck;
239         }
240     }
241 
242     /**
243      * Manages the {@link DomainSelectionConnection} instance and its related information.
244      */
245     @VisibleForTesting
246     protected class DomainSelectionConnectionHolder
247             implements DomainSelectionConnection.DomainSelectionConnectionCallback {
248         private final boolean mEmergency;
249         // Manages the pending request while selecting a proper domain.
250         private final List<PendingRequest> mPendingRequests = new ArrayList<>();
251         // Manages the domain selection connections: MO SMS or emergency SMS.
252         private DomainSelectionConnection mConnection;
253 
DomainSelectionConnectionHolder(boolean emergency)254         DomainSelectionConnectionHolder(boolean emergency) {
255             mEmergency = emergency;
256         }
257 
258         /**
259          * Returns a {@link DomainSelectionConnection} instance.
260          */
getConnection()261         public DomainSelectionConnection getConnection() {
262             return mConnection;
263         }
264 
265         /**
266          * Returns a list of {@link PendingRequest} that was added
267          * while the domain selection is performed.
268          */
getPendingRequests()269         public List<PendingRequest> getPendingRequests() {
270             return mPendingRequests;
271         }
272 
273         /**
274          * Checks whether or not the domain selection is requested.
275          * If there is no pending request, the domain selection request is needed to
276          * select a proper domain for MO SMS.
277          */
isDomainSelectionRequested()278         public boolean isDomainSelectionRequested() {
279             return !mPendingRequests.isEmpty();
280         }
281 
282         /**
283          * Checks whether or not this holder is for an emergency SMS.
284          */
isEmergency()285         public boolean isEmergency() {
286             return mEmergency;
287         }
288 
289         /**
290          * Clears all pending requests.
291          */
clearAllRequests()292         public void clearAllRequests() {
293             mPendingRequests.clear();
294         }
295 
296         /**
297          * Add a new pending request.
298          */
addRequest(@onNull PendingRequest request)299         public void addRequest(@NonNull PendingRequest request) {
300             mPendingRequests.add(request);
301         }
302 
303         /**
304          * Sets a {@link DomainSelectionConnection} instance.
305          */
setConnection(DomainSelectionConnection connection)306         public void setConnection(DomainSelectionConnection connection) {
307             mConnection = connection;
308         }
309 
310 
311         @Override
onSelectionTerminated(@isconnectCauses int cause)312         public void onSelectionTerminated(@DisconnectCauses int cause) {
313             notifyDomainSelectionTerminated(this);
314         }
315     }
316 
317     /** Manages the domain selection connections: MO SMS or emergency SMS. */
318     private DomainSelectionConnectionHolder mDscHolder;
319     private DomainSelectionConnectionHolder mEmergencyDscHolder;
320 
321     /**
322      * Puts a delivery pending tracker to the map based on the format.
323      *
324      * @param tracker the tracker awaiting a delivery status report.
325      */
putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker)326     public void putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker) {
327         if (isCdmaFormat(tracker.mFormat)) {
328             mDeliveryPendingMapFor3GPP2.put(tracker.mMessageRef, tracker);
329         } else {
330             mDeliveryPendingMapFor3GPP.put(tracker.mMessageRef, tracker);
331         }
332     }
333 
SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor)334     public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
335             SmsUsageMonitor usageMonitor) {
336         this(phone, storageMonitor, usageMonitor, phone.getLooper());
337     }
338 
339     @VisibleForTesting
SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor, Looper looper)340     public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
341             SmsUsageMonitor usageMonitor, Looper looper) {
342         super(looper);
343 
344         Rlog.d(TAG, "SmsDispatchersController created");
345 
346         mContext = phone.getContext();
347         mUsageMonitor = usageMonitor;
348         mCi = phone.mCi;
349         mPhone = phone;
350 
351         // Create dispatchers, inbound SMS handlers and
352         // broadcast undelivered messages in raw table.
353         mImsSmsDispatcher = new ImsSmsDispatcher(phone, this, ImsManager::getConnector);
354         mCdmaDispatcher = new CdmaSMSDispatcher(phone, this);
355         mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(),
356                 storageMonitor, phone, looper);
357         mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(),
358                 storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher, looper);
359         mGsmDispatcher = new GsmSMSDispatcher(phone, this, mGsmInboundSmsHandler);
360         SmsBroadcastUndelivered.initialize(phone.getContext(),
361                 mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
362         InboundSmsHandler.registerNewMessageNotificationActionHandler(phone.getContext());
363 
364         mCi.registerForOn(this, EVENT_RADIO_ON, null);
365         mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
366 
367         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
368         if (userManager.isUserUnlocked()) {
369             if (VDBG) {
370                 logd("SmsDispatchersController: user unlocked; registering for service"
371                         + "state changed");
372             }
373             mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
374             resetPartialSegmentWaitTimer();
375         } else {
376             if (VDBG) {
377                 logd("SmsDispatchersController: user locked; waiting for USER_UNLOCKED");
378             }
379             IntentFilter userFilter = new IntentFilter();
380             userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
381             mContext.registerReceiver(mBroadcastReceiver, userFilter);
382         }
383     }
384 
385     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
386         @Override
387         public void onReceive(final Context context, Intent intent) {
388             Rlog.d(TAG, "Received broadcast " + intent.getAction());
389             if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
390                 sendMessage(obtainMessage(EVENT_USER_UNLOCKED));
391             }
392         }
393     };
394 
dispose()395     public void dispose() {
396         mCi.unregisterForOn(this);
397         mCi.unregisterForImsNetworkStateChanged(this);
398         mPhone.unregisterForServiceStateChanged(this);
399         mGsmDispatcher.dispose();
400         mCdmaDispatcher.dispose();
401         mGsmInboundSmsHandler.dispose();
402         mCdmaInboundSmsHandler.dispose();
403         // Cancels the domain selection request if it's still in progress.
404         finishDomainSelection(mDscHolder);
405         finishDomainSelection(mEmergencyDscHolder);
406     }
407 
408     /**
409      * Handles events coming from the phone stack. Overridden from handler.
410      *
411      * @param msg the message to handle
412      */
413     @Override
handleMessage(Message msg)414     public void handleMessage(Message msg) {
415         AsyncResult ar;
416 
417         switch (msg.what) {
418             case EVENT_RADIO_ON:
419             case EVENT_IMS_STATE_CHANGED: // received unsol
420                 mCi.getImsRegistrationState(this.obtainMessage(EVENT_IMS_STATE_DONE));
421                 break;
422 
423             case EVENT_IMS_STATE_DONE:
424                 ar = (AsyncResult) msg.obj;
425 
426                 if (ar.exception == null) {
427                     updateImsInfo(ar);
428                 } else {
429                     Rlog.e(TAG, "IMS State query failed with exp "
430                             + ar.exception);
431                 }
432                 break;
433 
434             case EVENT_SERVICE_STATE_CHANGED:
435             case EVENT_SMS_HANDLER_EXITING_WAITING_STATE:
436                 reevaluateTimerStatus();
437                 break;
438 
439             case EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY:
440                 handlePartialSegmentTimerExpiry((Long) msg.obj);
441                 break;
442 
443             case EVENT_USER_UNLOCKED:
444                 if (VDBG) {
445                     logd("handleMessage: EVENT_USER_UNLOCKED");
446                 }
447                 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
448                 resetPartialSegmentWaitTimer();
449                 break;
450 
451             default:
452                 if (isCdmaMo()) {
453                     mCdmaDispatcher.handleMessage(msg);
454                 } else {
455                     mGsmDispatcher.handleMessage(msg);
456                 }
457         }
458     }
459 
getSmscAddressFromUSIMWithPhoneIdentity(String callingPkg)460     private String getSmscAddressFromUSIMWithPhoneIdentity(String callingPkg) {
461         final long identity = Binder.clearCallingIdentity();
462         try {
463             IccSmsInterfaceManager iccSmsIntMgr = mPhone.getIccSmsInterfaceManager();
464             if (iccSmsIntMgr != null) {
465                 return iccSmsIntMgr.getSmscAddressFromIccEf(callingPkg);
466             } else {
467                 Rlog.d(TAG, "getSmscAddressFromIccEf iccSmsIntMgr is null");
468             }
469         } finally {
470             Binder.restoreCallingIdentity(identity);
471         }
472         return null;
473     }
474 
reevaluateTimerStatus()475     private void reevaluateTimerStatus() {
476         long currentTime = System.currentTimeMillis();
477 
478         // Remove unhandled timer expiry message. A new message will be posted if needed.
479         removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY);
480         // Update timer duration elapsed time (add time since last IN_SERVICE to now).
481         // This is needed for IN_SERVICE as well as OUT_OF_SERVICE because same events can be
482         // received back to back
483         if (mLastInServiceTime != INVALID_TIME) {
484             mCurrentWaitElapsedDuration += (currentTime - mLastInServiceTime);
485         }
486 
487         if (VDBG) {
488             logd("reevaluateTimerStatus: currentTime: " + currentTime
489                     + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration);
490         }
491 
492         if (mCurrentWaitElapsedDuration > PARTIAL_SEGMENT_WAIT_DURATION) {
493             // handle this event as timer expiry
494             handlePartialSegmentTimerExpiry(mCurrentWaitStartTime);
495         } else {
496             if (isInService()) {
497                 handleInService(currentTime);
498             } else {
499                 handleOutOfService(currentTime);
500             }
501         }
502     }
503 
handleInService(long currentTime)504     private void handleInService(long currentTime) {
505         if (VDBG) {
506             logd("handleInService: timer expiry in "
507                     + (PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration) + "ms");
508         }
509 
510         // initialize mCurrentWaitStartTime if needed
511         if (mCurrentWaitStartTime == INVALID_TIME) mCurrentWaitStartTime = currentTime;
512 
513         // Post a message for timer expiry time. mCurrentWaitElapsedDuration is the duration already
514         // elapsed from the timer.
515         sendMessageDelayed(
516                 obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime),
517                 PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration);
518 
519         // update mLastInServiceTime as the current time
520         mLastInServiceTime = currentTime;
521     }
522 
handleOutOfService(long currentTime)523     private void handleOutOfService(long currentTime) {
524         if (VDBG) {
525             logd("handleOutOfService: currentTime: " + currentTime
526                     + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration);
527         }
528 
529         // mLastInServiceTime is not relevant now since state is OUT_OF_SERVICE; set it to INVALID
530         mLastInServiceTime = INVALID_TIME;
531     }
532 
handlePartialSegmentTimerExpiry(long waitTimerStart)533     private void handlePartialSegmentTimerExpiry(long waitTimerStart) {
534         if (mGsmInboundSmsHandler.getCurrentState().getName().equals("WaitingState")
535                 || mCdmaInboundSmsHandler.getCurrentState().getName().equals("WaitingState")) {
536             logd("handlePartialSegmentTimerExpiry: ignoring timer expiry as InboundSmsHandler is"
537                     + " in WaitingState");
538             return;
539         }
540 
541         if (VDBG) {
542             logd("handlePartialSegmentTimerExpiry: calling scanRawTable()");
543         }
544         // Timer expired. This indicates that device has been in service for
545         // PARTIAL_SEGMENT_WAIT_DURATION since waitTimerStart. Delete orphaned message segments
546         // older than waitTimerStart.
547         SmsBroadcastUndelivered.scanRawTable(mContext, waitTimerStart);
548         if (VDBG) {
549             logd("handlePartialSegmentTimerExpiry: scanRawTable() done");
550         }
551 
552         resetPartialSegmentWaitTimer();
553     }
554 
resetPartialSegmentWaitTimer()555     private void resetPartialSegmentWaitTimer() {
556         long currentTime = System.currentTimeMillis();
557 
558         removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY);
559         if (isInService()) {
560             if (VDBG) {
561                 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime
562                         + " IN_SERVICE");
563             }
564             mCurrentWaitStartTime = currentTime;
565             mLastInServiceTime = currentTime;
566             sendMessageDelayed(
567                     obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime),
568                     PARTIAL_SEGMENT_WAIT_DURATION);
569         } else {
570             if (VDBG) {
571                 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime
572                         + " not IN_SERVICE");
573             }
574             mCurrentWaitStartTime = INVALID_TIME;
575             mLastInServiceTime = INVALID_TIME;
576         }
577 
578         mCurrentWaitElapsedDuration = 0;
579     }
580 
isInService()581     private boolean isInService() {
582         ServiceState serviceState = mPhone.getServiceState();
583         return serviceState != null && serviceState.getState() == ServiceState.STATE_IN_SERVICE;
584     }
585 
setImsSmsFormat(int format)586     private void setImsSmsFormat(int format) {
587         switch (format) {
588             case PhoneConstants.PHONE_TYPE_GSM:
589                 mImsSmsFormat = SmsConstants.FORMAT_3GPP;
590                 break;
591             case PhoneConstants.PHONE_TYPE_CDMA:
592                 mImsSmsFormat = SmsConstants.FORMAT_3GPP2;
593                 break;
594             default:
595                 mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN;
596                 break;
597         }
598     }
599 
updateImsInfo(AsyncResult ar)600     private void updateImsInfo(AsyncResult ar) {
601         int[] responseArray = (int[]) ar.result;
602         setImsSmsFormat(responseArray[1]);
603         mIms = responseArray[0] == 1 && !SmsConstants.FORMAT_UNKNOWN.equals(mImsSmsFormat);
604         Rlog.d(TAG, "IMS registration state: " + mIms + " format: " + mImsSmsFormat);
605     }
606 
607     /**
608      * Inject an SMS PDU into the android platform only if it is class 1.
609      *
610      * @param pdu is the byte array of pdu to be injected into android telephony layer
611      * @param format is the format of SMS pdu (3gpp or 3gpp2)
612      * @param callback if not NULL this callback is triggered when the message is successfully
613      *                 received by the android telephony layer. This callback is triggered at
614      *                 the same time an SMS received from radio is responded back.
615      */
616     @VisibleForTesting
injectSmsPdu(byte[] pdu, String format, boolean isOverIms, SmsInjectionCallback callback)617     public void injectSmsPdu(byte[] pdu, String format, boolean isOverIms,
618             SmsInjectionCallback callback) {
619         // TODO We need to decide whether we should allow injecting GSM(3gpp)
620         // SMS pdus when the phone is camping on CDMA(3gpp2) network and vice versa.
621         android.telephony.SmsMessage msg =
622                 android.telephony.SmsMessage.createFromPdu(pdu, format);
623         injectSmsPdu(msg, format, callback, false /* ignoreClass */, isOverIms, 0 /* unused */);
624     }
625 
626     @VisibleForTesting
setImsSmsDispatcher(ImsSmsDispatcher imsSmsDispatcher)627     public void setImsSmsDispatcher(ImsSmsDispatcher imsSmsDispatcher) {
628         mImsSmsDispatcher = imsSmsDispatcher;
629     }
630 
631     /**
632      * Inject an SMS PDU into the android platform.
633      *
634      * @param msg is the {@link SmsMessage} to be injected into android telephony layer
635      * @param format is the format of SMS pdu (3gpp or 3gpp2)
636      * @param callback if not NULL this callback is triggered when the message is successfully
637      *                 received by the android telephony layer. This callback is triggered at
638      *                 the same time an SMS received from radio is responded back.
639      * @param ignoreClass if set to false, this method will inject class 1 sms only.
640      */
641     @VisibleForTesting
injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, boolean ignoreClass, boolean isOverIms, int token)642     public void injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback,
643             boolean ignoreClass, boolean isOverIms, int token) {
644         Rlog.d(TAG, "SmsDispatchersController:injectSmsPdu");
645         try {
646             if (msg == null) {
647                 Rlog.e(TAG, "injectSmsPdu: createFromPdu returned null");
648                 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR);
649                 return;
650             }
651 
652             if (!ignoreClass
653                     && msg.getMessageClass() != android.telephony.SmsMessage.MessageClass.CLASS_1) {
654                 Rlog.e(TAG, "injectSmsPdu: not class 1");
655                 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR);
656                 return;
657             }
658 
659             AsyncResult ar = new AsyncResult(callback, msg, null);
660 
661             if (format.equals(SmsConstants.FORMAT_3GPP)) {
662                 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg
663                         + ", format=" + format + "to mGsmInboundSmsHandler");
664                 mGsmInboundSmsHandler.sendMessage(
665                         InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, token, ar);
666             } else if (format.equals(SmsConstants.FORMAT_3GPP2)) {
667                 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg
668                         + ", format=" + format + "to mCdmaInboundSmsHandler");
669                 mCdmaInboundSmsHandler.sendMessage(
670                         InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, 0, ar);
671             } else {
672                 // Invalid pdu format.
673                 Rlog.e(TAG, "Invalid pdu format: " + format);
674                 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR);
675             }
676         } catch (Exception e) {
677             Rlog.e(TAG, "injectSmsPdu failed: ", e);
678             callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR);
679         }
680     }
681 
682     /**
683      * sets ImsManager object.
684      *
685      * @param imsManager holds a valid object or a null for setting
686      */
setImsManager(ImsManager imsManager)687     public boolean setImsManager(ImsManager imsManager) {
688         if (mGsmInboundSmsHandler != null) {
689             mGsmInboundSmsHandler.setImsManager(imsManager);
690             return true;
691         }
692         return false;
693     }
694 
695     /**
696      * Retry the message along to the radio.
697      *
698      * @param tracker holds the SMS message to send
699      */
sendRetrySms(SMSDispatcher.SmsTracker tracker)700     public void sendRetrySms(SMSDispatcher.SmsTracker tracker) {
701         boolean retryUsingImsService = false;
702 
703         if (!tracker.mUsesImsServiceForIms) {
704             if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
705                 DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
706 
707                 // If the DomainSelectionConnection is not available,
708                 // fallback to the legacy implementation.
709                 if (holder != null && holder.getConnection() != null) {
710                     sendSmsUsingDomainSelection(holder,
711                             new PendingRequest(PendingRequest.TYPE_RETRY_SMS, tracker,
712                                     null, null, null, null, null, false, null, 0, null, null, false,
713                                     0, false, 0, 0L, false),
714                             "sendRetrySms");
715                     return;
716                 }
717             }
718 
719             if (mImsSmsDispatcher.isAvailable()) {
720                 // If this tracker has not been handled by ImsSmsDispatcher yet and IMS Service is
721                 // available now, retry this failed tracker using IMS Service.
722                 retryUsingImsService = true;
723             }
724         }
725 
726         sendRetrySms(tracker, retryUsingImsService);
727     }
728 
729     /**
730      * Retry the message along to the radio.
731      *
732      * @param tracker holds the SMS message to send
733      * @param retryUsingImsService a flag to indicate whether the retry SMS can use the ImsService
734      */
sendRetrySms(SMSDispatcher.SmsTracker tracker, boolean retryUsingImsService)735     public void sendRetrySms(SMSDispatcher.SmsTracker tracker, boolean retryUsingImsService) {
736         String oldFormat = tracker.mFormat;
737         // If retryUsingImsService is true, newFormat will be IMS SMS format. Otherwise, newFormat
738         // will be based on voice technology.
739         String newFormat =
740                 retryUsingImsService
741                         ? mImsSmsDispatcher.getFormat()
742                         : (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType())
743                                 ? mCdmaDispatcher.getFormat()
744                                 : mGsmDispatcher.getFormat();
745 
746         Rlog.d(TAG, "old format(" + oldFormat + ") ==> new format (" + newFormat + ")");
747         if (!oldFormat.equals(newFormat)) {
748             // format didn't match, need to re-encode.
749             HashMap map = tracker.getData();
750 
751             // to re-encode, fields needed are: scAddr, destAddr and text if originally sent as
752             // sendText or data and destPort if originally sent as sendData.
753             if (!(map.containsKey("scAddr") && map.containsKey("destAddr")
754                     && (map.containsKey("text")
755                     || (map.containsKey("data") && map.containsKey("destPort"))))) {
756                 // should never come here...
757                 Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!");
758                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
759                 return;
760             }
761             String scAddr = (String) map.get("scAddr");
762             String destAddr = (String) map.get("destAddr");
763             if (destAddr == null) {
764                 Rlog.e(TAG, "sendRetrySms failed due to null destAddr");
765                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
766                 return;
767             }
768 
769             SmsMessageBase.SubmitPduBase pdu = null;
770             // figure out from tracker if this was sendText/Data
771             if (map.containsKey("text")) {
772                 String text = (String) map.get("text");
773                 Rlog.d(TAG, "sms failed was text with length: "
774                         + (text == null ? null : text.length()));
775 
776                 if (isCdmaFormat(newFormat)) {
777                     pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
778                             scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
779                 } else {
780                     pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
781                             scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null,
782                             0, 0, 0, -1, tracker.mMessageRef);
783                 }
784             } else if (map.containsKey("data")) {
785                 byte[] data = (byte[]) map.get("data");
786                 Integer destPort = (Integer) map.get("destPort");
787                 Rlog.d(TAG, "sms failed was data with length: "
788                         + (data == null ? null : data.length));
789 
790                 if (isCdmaFormat(newFormat)) {
791                     pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
792                             scAddr, destAddr, destPort.intValue(), data,
793                             (tracker.mDeliveryIntent != null));
794                 } else {
795                     pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
796                             scAddr, destAddr, destPort.intValue(), data,
797                             (tracker.mDeliveryIntent != null), tracker.mMessageRef);
798                 }
799             }
800 
801             if (pdu == null) {
802                 Rlog.e(TAG, String.format("sendRetrySms failed to encode message."
803                         + "scAddr: %s, "
804                         + "destPort: %s", scAddr, map.get("destPort")));
805                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
806                 return;
807             }
808             // replace old smsc and pdu with newly encoded ones
809             map.put("smsc", pdu.encodedScAddress);
810             map.put("pdu", pdu.encodedMessage);
811             tracker.mFormat = newFormat;
812         }
813 
814         SMSDispatcher dispatcher =
815                 retryUsingImsService
816                         ? mImsSmsDispatcher
817                         : (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher;
818 
819         dispatcher.sendSms(tracker);
820     }
821 
822     /**
823      * Memory Available Event
824      * @param result callback message
825      */
reportSmsMemoryStatus(Message result)826     public void reportSmsMemoryStatus(Message result) {
827         Rlog.d(TAG, "reportSmsMemoryStatus: ");
828         try {
829             mImsSmsDispatcher.onMemoryAvailable();
830             AsyncResult.forMessage(result, null, null);
831             result.sendToTarget();
832         } catch (Exception e) {
833             Rlog.e(TAG, "reportSmsMemoryStatus Failed ", e);
834             AsyncResult.forMessage(result, null, e);
835             result.sendToTarget();
836         }
837     }
838 
839     /**
840      * SMS over IMS is supported if IMS is registered and SMS is supported on IMS.
841      *
842      * @return true if SMS over IMS is supported via an IMS Service or mIms is true for the older
843      *         implementation. Otherwise, false.
844      */
isIms()845     public boolean isIms() {
846         return mImsSmsDispatcher.isAvailable() ? true : mIms;
847     }
848 
849     /**
850      * Gets SMS format supported on IMS.
851      *
852      * @return the SMS format from an IMS Service if available. Otherwise, mImsSmsFormat for the
853      *         older implementation.
854      */
getImsSmsFormat()855     public String getImsSmsFormat() {
856         return mImsSmsDispatcher.isAvailable() ? mImsSmsDispatcher.getFormat() : mImsSmsFormat;
857     }
858 
859     /**
860      * Determines whether or not to use CDMA format for MO SMS.
861      * If SMS over IMS is supported, then format is based on IMS SMS format,
862      * otherwise format is based on current phone type.
863      *
864      * @return true if Cdma format should be used for MO SMS, false otherwise.
865      */
isCdmaMo()866     protected boolean isCdmaMo() {
867         if (!isIms()) {
868             // IMS is not registered, use Voice technology to determine SMS format.
869             return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType());
870         }
871         // IMS is registered with SMS support
872         return isCdmaFormat(getImsSmsFormat());
873     }
874 
875     /**
876      * Determines whether or not format given is CDMA format.
877      *
878      * @param format
879      * @return true if format given is CDMA format, false otherwise.
880      */
isCdmaFormat(String format)881     public boolean isCdmaFormat(String format) {
882         return (mCdmaDispatcher.getFormat().equals(format));
883     }
884 
885     /** Sets a proxy interface for accessing the methods of {@link DomainSelectionResolver}. */
886     @VisibleForTesting
setDomainSelectionResolverProxy(@onNull DomainSelectionResolverProxy proxy)887     public void setDomainSelectionResolverProxy(@NonNull DomainSelectionResolverProxy proxy) {
888         mDomainSelectionResolverProxy = proxy;
889     }
890 
891     /**
892      * Determines whether or not to use CDMA format for MO SMS when the domain selection uses.
893      * If the domain is {@link NetworkRegistrationInfo#DOMAIN_PS}, then format is based on
894      * IMS SMS format, otherwise format is based on current phone type.
895      *
896      * @return {@code true} if CDMA format should be used for MO SMS, {@code false} otherwise.
897      */
isCdmaMo(@etworkRegistrationInfo.Domain int domain)898     private boolean isCdmaMo(@NetworkRegistrationInfo.Domain int domain) {
899         if (domain != NetworkRegistrationInfo.DOMAIN_PS) {
900             // IMS is not registered, use voice technology to determine SMS format.
901             return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType());
902         }
903         // IMS is registered with SMS support
904         return isCdmaFormat(mImsSmsDispatcher.getFormat());
905     }
906 
907     /**
908      * Returns a {@link DomainSelectionConnectionHolder} according to the flag specified.
909      *
910      * @param emergency The flag to indicate that the domain selection is for an emergency SMS.
911      * @return A {@link DomainSelectionConnectionHolder} instance or null.
912      */
913     @VisibleForTesting
914     @Nullable
getDomainSelectionConnectionHolder( boolean emergency)915     protected DomainSelectionConnectionHolder getDomainSelectionConnectionHolder(
916             boolean emergency) {
917         return emergency ? mEmergencyDscHolder : mDscHolder;
918     }
919 
920     /**
921      * Returns a {@link DomainSelectionConnectionHolder} if the domain selection supports,
922      * return null otherwise.
923      *
924      * @param emergency The flag to indicate that the domain selection is for an emergency SMS.
925      * @return A {@link DomainSelectionConnectionHolder} that grabs the
926      *         {@link DomainSelectionConnection} and its related information to use the domain
927      *         selection architecture.
928      */
getDomainSelectionConnection(boolean emergency)929     private DomainSelectionConnectionHolder getDomainSelectionConnection(boolean emergency) {
930         DomainSelectionConnectionHolder holder = getDomainSelectionConnectionHolder(emergency);
931         DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null;
932         boolean created = false;
933 
934         if (connection == null) {
935             connection = mDomainSelectionResolverProxy.getDomainSelectionConnection(
936                     mPhone, DomainSelectionService.SELECTOR_TYPE_SMS, emergency);
937 
938             if (connection == null) {
939                 // Domain selection architecture is not supported.
940                 // Use the legacy architecture.
941                 return null;
942             }
943 
944             created = true;
945         }
946 
947         if (holder == null) {
948             holder = new DomainSelectionConnectionHolder(emergency);
949 
950             if (emergency) {
951                 mEmergencyDscHolder = holder;
952             } else {
953                 mDscHolder = holder;
954             }
955         }
956 
957         holder.setConnection(connection);
958 
959         return holder;
960     }
961 
962     /**
963      * Requests the domain selection for MO SMS.
964      *
965      * @param holder The {@link DomainSelectionConnectionHolder} that contains the
966      *               {@link DomainSelectionConnection} and its related information.
967      */
requestDomainSelection(@onNull DomainSelectionConnectionHolder holder)968     private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder) {
969         DomainSelectionService.SelectionAttributes attr =
970                 new DomainSelectionService.SelectionAttributes.Builder(mPhone.getPhoneId(),
971                         mPhone.getSubId(), DomainSelectionService.SELECTOR_TYPE_SMS)
972                 .setEmergency(holder.isEmergency())
973                 .build();
974 
975         if (holder.isEmergency()) {
976             EmergencySmsDomainSelectionConnection emergencyConnection =
977                     (EmergencySmsDomainSelectionConnection) holder.getConnection();
978             CompletableFuture<Integer> future =
979                     emergencyConnection.requestDomainSelection(attr, holder);
980             future.thenAcceptAsync((domain) -> {
981                 if (VDBG) {
982                     logd("requestDomainSelection(emergency): domain="
983                             + DomainSelectionService.getDomainName(domain));
984                 }
985                 sendAllPendingRequests(holder, domain);
986                 finishDomainSelection(holder);
987             }, this::post);
988         } else {
989             SmsDomainSelectionConnection connection =
990                     (SmsDomainSelectionConnection) holder.getConnection();
991             CompletableFuture<Integer> future = connection.requestDomainSelection(attr, holder);
992             future.thenAcceptAsync((domain) -> {
993                 if (VDBG) {
994                     logd("requestDomainSelection: domain="
995                             + DomainSelectionService.getDomainName(domain));
996                 }
997                 sendAllPendingRequests(holder, domain);
998                 finishDomainSelection(holder);
999             }, this::post);
1000         }
1001     }
1002 
1003     /**
1004      * Sends a SMS after selecting the domain via the domain selection service.
1005      *
1006      * @param holder The {@link DomainSelectionConnectionHolder} that contains the
1007      *               {@link DomainSelectionConnection} and its related information.
1008      * @param request The {@link PendingRequest} that stores the SMS request
1009      *                (data, text, multipart text) to be sent.
1010      * @param logTag The log tag to display which method called this method.
1011      */
sendSmsUsingDomainSelection(@onNull DomainSelectionConnectionHolder holder, @NonNull PendingRequest request, @NonNull String logTag)1012     private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
1013             @NonNull PendingRequest request, @NonNull String logTag) {
1014         boolean isDomainSelectionRequested = holder.isDomainSelectionRequested();
1015         // The domain selection is in progress so waits for the result of
1016         // the domain selection by adding this request to the pending list.
1017         holder.addRequest(request);
1018 
1019         if (!isDomainSelectionRequested) {
1020             if (VDBG) {
1021                 logd("requestDomainSelection: " + logTag);
1022             }
1023             requestDomainSelection(holder);
1024         }
1025     }
1026 
1027     /**
1028      * Finishes the domain selection for MO SMS.
1029      *
1030      * @param holder The {@link DomainSelectionConnectionHolder} object that is being finished.
1031      */
finishDomainSelection(DomainSelectionConnectionHolder holder)1032     private void finishDomainSelection(DomainSelectionConnectionHolder holder) {
1033         DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null;
1034 
1035         if (connection != null) {
1036             // After this method is called, the domain selection service will clean up
1037             // its resources and finish the procedure that are related to the current domain
1038             // selection request.
1039             connection.finishSelection();
1040         }
1041 
1042         if (holder != null) {
1043             final List<PendingRequest> pendingRequests = holder.getPendingRequests();
1044 
1045             logd("finishDomainSelection: pendingRequests=" + pendingRequests.size());
1046 
1047             for (PendingRequest r : pendingRequests) {
1048                 triggerSentIntentForFailure(r.sentIntents);
1049             }
1050 
1051             holder.clearAllRequests();
1052             holder.setConnection(null);
1053         }
1054     }
1055 
1056     /**
1057      * Notifies the application that MO SMS is not sent by the error of domain selection.
1058      *
1059      * @param holder The {@link DomainSelectionConnectionHolder} object that is being terminated.
1060      */
notifyDomainSelectionTerminated(@onNull DomainSelectionConnectionHolder holder)1061     private void notifyDomainSelectionTerminated(@NonNull DomainSelectionConnectionHolder holder) {
1062         final List<PendingRequest> pendingRequests = holder.getPendingRequests();
1063 
1064         logd("notifyDomainSelectionTerminated: pendingRequests=" + pendingRequests.size());
1065 
1066         for (PendingRequest r : pendingRequests) {
1067             triggerSentIntentForFailure(r.sentIntents);
1068         }
1069 
1070         holder.setConnection(null);
1071         holder.clearAllRequests();
1072     }
1073 
1074     /**
1075      * Sends all pending requests for MO SMS.
1076      *
1077      * @param holder The {@link DomainSelectionConnectionHolder} object that all the pending
1078      *               requests are handled.
1079      * @param domain The domain where the SMS is being sent, which can be one of the following:
1080      *               - {@link NetworkRegistrationInfo#DOMAIN_PS}
1081      *               - {@link NetworkRegistrationInfo#DOMAIN_CS}
1082      */
sendAllPendingRequests(@onNull DomainSelectionConnectionHolder holder, @NetworkRegistrationInfo.Domain int domain)1083     private void sendAllPendingRequests(@NonNull DomainSelectionConnectionHolder holder,
1084             @NetworkRegistrationInfo.Domain int domain) {
1085         final List<PendingRequest> pendingRequests = holder.getPendingRequests();
1086 
1087         if (VDBG) {
1088             logd("sendAllPendingRequests: domain=" + DomainSelectionService.getDomainName(domain)
1089                     + ", size=" + pendingRequests.size());
1090         }
1091 
1092         for (PendingRequest r : pendingRequests) {
1093             switch (r.type) {
1094                 case PendingRequest.TYPE_DATA:
1095                     sendData(domain, r);
1096                     break;
1097                 case PendingRequest.TYPE_TEXT:
1098                     sendText(domain, r);
1099                     break;
1100                 case PendingRequest.TYPE_MULTIPART_TEXT:
1101                     sendMultipartText(domain, r);
1102                     break;
1103                 case PendingRequest.TYPE_RETRY_SMS:
1104                     sendRetrySms(r.tracker, (domain == NetworkRegistrationInfo.DOMAIN_PS));
1105                     break;
1106                 default:
1107                     // Not reachable.
1108                     break;
1109             }
1110         }
1111 
1112         holder.clearAllRequests();
1113     }
1114 
1115     /**
1116      * Sends a data based SMS to a specific application port.
1117      *
1118      * @param domain The domain where the SMS is being sent, which can be one of the following:
1119      *               - {@link NetworkRegistrationInfo#DOMAIN_PS}
1120      *               - {@link NetworkRegistrationInfo#DOMAIN_CS}
1121      * @param request The pending request for MO SMS.
1122      */
sendData(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1123     private void sendData(@NetworkRegistrationInfo.Domain int domain,
1124             @NonNull PendingRequest request) {
1125         if (domain == NetworkRegistrationInfo.DOMAIN_PS) {
1126             mImsSmsDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr,
1127                     request.destPort, request.data, request.sentIntents.get(0),
1128                     request.deliveryIntents.get(0), request.isForVvm);
1129         } else if (isCdmaMo(domain)) {
1130             mCdmaDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr,
1131                     request.destPort, request.data, request.sentIntents.get(0),
1132                     request.deliveryIntents.get(0), request.isForVvm);
1133         } else {
1134             mGsmDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr,
1135                     request.destPort, request.data, request.sentIntents.get(0),
1136                     request.deliveryIntents.get(0), request.isForVvm);
1137         }
1138     }
1139 
1140     /**
1141      * Sends a text based SMS.
1142      *
1143      * @param domain The domain where the SMS is being sent, which can be one of the following:
1144      *               - {@link NetworkRegistrationInfo#DOMAIN_PS}
1145      *               - {@link NetworkRegistrationInfo#DOMAIN_CS}
1146      * @param request The pending request for MO SMS.
1147      */
sendText(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1148     private void sendText(@NetworkRegistrationInfo.Domain int domain,
1149             @NonNull PendingRequest request) {
1150         if (domain == NetworkRegistrationInfo.DOMAIN_PS) {
1151             mImsSmsDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0),
1152                     request.sentIntents.get(0), request.deliveryIntents.get(0),
1153                     request.messageUri, request.callingPackage, request.persistMessage,
1154                     request.priority, false /*request.expectMore*/, request.validityPeriod,
1155                     request.isForVvm, request.messageId, request.skipShortCodeCheck);
1156         } else {
1157             if (isCdmaMo(domain)) {
1158                 mCdmaDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0),
1159                         request.sentIntents.get(0), request.deliveryIntents.get(0),
1160                         request.messageUri, request.callingPackage, request.persistMessage,
1161                         request.priority, request.expectMore, request.validityPeriod,
1162                         request.isForVvm, request.messageId, request.skipShortCodeCheck);
1163             } else {
1164                 mGsmDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0),
1165                         request.sentIntents.get(0), request.deliveryIntents.get(0),
1166                         request.messageUri, request.callingPackage, request.persistMessage,
1167                         request.priority, request.expectMore, request.validityPeriod,
1168                         request.isForVvm, request.messageId, request.skipShortCodeCheck);
1169             }
1170         }
1171     }
1172 
1173     /**
1174      * Sends a multi-part text based SMS.
1175      *
1176      * @param domain The domain where the SMS is being sent, which can be one of the following:
1177      *               - {@link NetworkRegistrationInfo#DOMAIN_PS}
1178      *               - {@link NetworkRegistrationInfo#DOMAIN_CS}
1179      * @param request The pending request for MO SMS.
1180      */
sendMultipartText(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1181     private void sendMultipartText(@NetworkRegistrationInfo.Domain int domain,
1182             @NonNull PendingRequest request) {
1183         if (domain == NetworkRegistrationInfo.DOMAIN_PS) {
1184             mImsSmsDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts,
1185                     request.sentIntents, request.deliveryIntents, request.messageUri,
1186                     request.callingPackage, request.persistMessage, request.priority,
1187                     false /*request.expectMore*/, request.validityPeriod, request.messageId);
1188         } else {
1189             if (isCdmaMo(domain)) {
1190                 mCdmaDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts,
1191                         request.sentIntents, request.deliveryIntents, request.messageUri,
1192                         request.callingPackage, request.persistMessage, request.priority,
1193                         request.expectMore, request.validityPeriod, request.messageId);
1194             } else {
1195                 mGsmDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts,
1196                         request.sentIntents, request.deliveryIntents, request.messageUri,
1197                         request.callingPackage, request.persistMessage, request.priority,
1198                         request.expectMore, request.validityPeriod, request.messageId);
1199             }
1200         }
1201     }
1202 
triggerSentIntentForFailure(@onNull PendingIntent sentIntent)1203     private void triggerSentIntentForFailure(@NonNull PendingIntent sentIntent) {
1204         try {
1205             sentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
1206         } catch (CanceledException e) {
1207             logd("Intent has been canceled!");
1208         }
1209     }
1210 
triggerSentIntentForFailure(@onNull List<PendingIntent> sentIntents)1211     private void triggerSentIntentForFailure(@NonNull List<PendingIntent> sentIntents) {
1212         for (PendingIntent sentIntent : sentIntents) {
1213             triggerSentIntentForFailure(sentIntent);
1214         }
1215     }
1216 
1217     /**
1218      * Creates an ArrayList object from any object.
1219      */
asArrayList(T object)1220     private static <T> ArrayList<T> asArrayList(T object) {
1221         ArrayList<T> list = new ArrayList<>();
1222         list.add(object);
1223         return list;
1224     }
1225 
1226     /**
1227      * Send a data based SMS to a specific application port.
1228      *
1229      * @param callingPackage the package name of the calling app
1230      * @param destAddr the address to send the message to
1231      * @param scAddr is the service center address or null to use
1232      *  the current default SMSC
1233      * @param destPort the port to deliver the message to
1234      * @param data the body of the message to send
1235      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1236      *  broadcast when the message is successfully sent, or failed.
1237      *  The result code will be <code>Activity.RESULT_OK<code> for success,
1238      *  or one of these errors:<br>
1239      *  <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br>
1240      *  <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br>
1241      *  <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br>
1242      *  <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br>
1243      *  <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br>
1244      *  <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
1245      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
1246      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
1247      *  <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br>
1248      *  <code>SmsManager.RESULT_NETWORK_REJECT</code><br>
1249      *  <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br>
1250      *  <code>SmsManager.RESULT_INVALID_STATE</code><br>
1251      *  <code>SmsManager.RESULT_NO_MEMORY</code><br>
1252      *  <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br>
1253      *  <code>SmsManager.RESULT_SYSTEM_ERROR</code><br>
1254      *  <code>SmsManager.RESULT_MODEM_ERROR</code><br>
1255      *  <code>SmsManager.RESULT_NETWORK_ERROR</code><br>
1256      *  <code>SmsManager.RESULT_ENCODING_ERROR</code><br>
1257      *  <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br>
1258      *  <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br>
1259      *  <code>SmsManager.RESULT_INTERNAL_ERROR</code><br>
1260      *  <code>SmsManager.RESULT_NO_RESOURCES</code><br>
1261      *  <code>SmsManager.RESULT_CANCELLED</code><br>
1262      *  <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br>
1263      *  <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br>
1264      *  <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
1265      *  <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br>
1266      *  <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
1267      *  <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
1268      *  <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br>
1269      *  <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br>
1270      *  <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br>
1271      *  <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
1272      *  <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
1273      *  <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br>
1274      *  <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br>
1275      *  <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br>
1276      *  <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br>
1277      *  <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
1278      *  <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br>
1279      *  <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br>
1280      *  <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br>
1281      *  <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
1282      *  <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br>
1283      *  <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br>
1284      *  <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br>
1285      *  <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
1286      *  <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br>
1287      *  <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br>
1288      *  <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
1289      *  <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br>
1290      *  <code>SmsManager.RESULT_RIL_CANCELLED</code><br>
1291      *  <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br>
1292      *  <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br>
1293      *  <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br>
1294      *  <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br>
1295      *  For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
1296      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
1297      *  value, generally only useful for troubleshooting.<br>
1298      *  The per-application based SMS control checks sentIntent. If sentIntent
1299      *  is NULL the caller will be checked against all unknown applications,
1300      *  which cause smaller number of SMS to be sent in checking period.
1301      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
1302      *  broadcast when the message is delivered to the recipient.  The
1303      *  raw pdu of the status report is in the extended data ("pdu").
1304      */
sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)1305     protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort,
1306             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) {
1307         if (TextUtils.isEmpty(scAddr)) {
1308             scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPackage);
1309         }
1310 
1311         if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
1312             DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
1313 
1314             // If the DomainSelectionConnection is not available,
1315             // fallback to the legacy implementation.
1316             if (holder != null && holder.getConnection() != null) {
1317                 sendSmsUsingDomainSelection(holder,
1318                         new PendingRequest(PendingRequest.TYPE_DATA, null, callingPackage,
1319                                 destAddr, scAddr, asArrayList(sentIntent),
1320                                 asArrayList(deliveryIntent), isForVvm, data, destPort, null, null,
1321                                 false, 0, false, 0, 0L, false),
1322                         "sendData");
1323                 return;
1324             }
1325         }
1326 
1327         if (mImsSmsDispatcher.isAvailable()) {
1328             mImsSmsDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
1329                     deliveryIntent, isForVvm);
1330         } else if (isCdmaMo()) {
1331             mCdmaDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
1332                     deliveryIntent, isForVvm);
1333         } else {
1334             mGsmDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
1335                     deliveryIntent, isForVvm);
1336         }
1337     }
1338 
1339     /**
1340      * Send a text based SMS.
1341      *
1342      * @param destAddr the address to send the message to
1343      * @param scAddr is the service center address or null to use
1344      *  the current default SMSC
1345      * @param text the body of the message to send
1346      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1347      *  broadcast when the message is successfully sent, or failed.
1348      *  The result code will be <code>Activity.RESULT_OK<code> for success,
1349      *  or one of these errors:<br>
1350      *  <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br>
1351      *  <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br>
1352      *  <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br>
1353      *  <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br>
1354      *  <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br>
1355      *  <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
1356      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
1357      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
1358      *  <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br>
1359      *  <code>SmsManager.RESULT_NETWORK_REJECT</code><br>
1360      *  <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br>
1361      *  <code>SmsManager.RESULT_INVALID_STATE</code><br>
1362      *  <code>SmsManager.RESULT_NO_MEMORY</code><br>
1363      *  <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br>
1364      *  <code>SmsManager.RESULT_SYSTEM_ERROR</code><br>
1365      *  <code>SmsManager.RESULT_MODEM_ERROR</code><br>
1366      *  <code>SmsManager.RESULT_NETWORK_ERROR</code><br>
1367      *  <code>SmsManager.RESULT_ENCODING_ERROR</code><br>
1368      *  <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br>
1369      *  <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br>
1370      *  <code>SmsManager.RESULT_INTERNAL_ERROR</code><br>
1371      *  <code>SmsManager.RESULT_NO_RESOURCES</code><br>
1372      *  <code>SmsManager.RESULT_CANCELLED</code><br>
1373      *  <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br>
1374      *  <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br>
1375      *  <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
1376      *  <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br>
1377      *  <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
1378      *  <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
1379      *  <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br>
1380      *  <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br>
1381      *  <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br>
1382      *  <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
1383      *  <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
1384      *  <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br>
1385      *  <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br>
1386      *  <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br>
1387      *  <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br>
1388      *  <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
1389      *  <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br>
1390      *  <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br>
1391      *  <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br>
1392      *  <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
1393      *  <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br>
1394      *  <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br>
1395      *  <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br>
1396      *  <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
1397      *  <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br>
1398      *  <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br>
1399      *  <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
1400      *  <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br>
1401      *  <code>SmsManager.RESULT_RIL_CANCELLED</code><br>
1402      *  <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br>
1403      *  <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br>
1404      *  <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br>
1405      *  <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br>
1406      *  For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
1407      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
1408      *  value, generally only useful for troubleshooting.<br>
1409      *  The per-application based SMS control checks sentIntent. If sentIntent
1410      *  is NULL the caller will be checked against all unknown applications,
1411      *  which cause smaller number of SMS to be sent in checking period.
1412      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
1413      *  broadcast when the message is delivered to the recipient.  The
1414      * @param messageUri optional URI of the message if it is already stored in the system
1415      * @param callingPkg the calling package name
1416      * @param persistMessage whether to save the sent message into SMS DB for a
1417      *  non-default SMS app.
1418      * @param priority Priority level of the message
1419      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
1420      *  ---------------------------------
1421      *  PRIORITY      | Level of Priority
1422      *  ---------------------------------
1423      *      '00'      |     Normal
1424      *      '01'      |     Interactive
1425      *      '10'      |     Urgent
1426      *      '11'      |     Emergency
1427      *  ----------------------------------
1428      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
1429      * @param expectMore is a boolean to indicate the sending messages through same link or not.
1430      * @param validityPeriod Validity Period of the message in mins.
1431      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
1432      *  Validity Period(Minimum) -> 5 mins
1433      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
1434      *  Any Other values included Negative considered as Invalid Validity Period of the message.
1435      */
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)1436     public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent,
1437             PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage,
1438             int priority, boolean expectMore, int validityPeriod, boolean isForVvm,
1439             long messageId) {
1440         sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg,
1441                 persistMessage, priority, expectMore, validityPeriod, isForVvm, messageId, false);
1442     }
1443 
1444     /**
1445      * Send a text based SMS.
1446      *
1447      * @param destAddr the address to send the message to
1448      * @param scAddr is the service center address or null to use
1449      *  the current default SMSC
1450      * @param text the body of the message to send
1451      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1452      *  broadcast when the message is successfully sent, or failed.
1453      *  The result code will be <code>Activity.RESULT_OK<code> for success,
1454      *  or one of these errors:<br>
1455      *  <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br>
1456      *  <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br>
1457      *  <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br>
1458      *  <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br>
1459      *  <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br>
1460      *  <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
1461      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
1462      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
1463      *  <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br>
1464      *  <code>SmsManager.RESULT_NETWORK_REJECT</code><br>
1465      *  <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br>
1466      *  <code>SmsManager.RESULT_INVALID_STATE</code><br>
1467      *  <code>SmsManager.RESULT_NO_MEMORY</code><br>
1468      *  <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br>
1469      *  <code>SmsManager.RESULT_SYSTEM_ERROR</code><br>
1470      *  <code>SmsManager.RESULT_MODEM_ERROR</code><br>
1471      *  <code>SmsManager.RESULT_NETWORK_ERROR</code><br>
1472      *  <code>SmsManager.RESULT_ENCODING_ERROR</code><br>
1473      *  <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br>
1474      *  <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br>
1475      *  <code>SmsManager.RESULT_INTERNAL_ERROR</code><br>
1476      *  <code>SmsManager.RESULT_NO_RESOURCES</code><br>
1477      *  <code>SmsManager.RESULT_CANCELLED</code><br>
1478      *  <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br>
1479      *  <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br>
1480      *  <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
1481      *  <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br>
1482      *  <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
1483      *  <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
1484      *  <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br>
1485      *  <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br>
1486      *  <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br>
1487      *  <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
1488      *  <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
1489      *  <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br>
1490      *  <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br>
1491      *  <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br>
1492      *  <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br>
1493      *  <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
1494      *  <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br>
1495      *  <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br>
1496      *  <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br>
1497      *  <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
1498      *  <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br>
1499      *  <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br>
1500      *  <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br>
1501      *  <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
1502      *  <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br>
1503      *  <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br>
1504      *  <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
1505      *  <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br>
1506      *  <code>SmsManager.RESULT_RIL_CANCELLED</code><br>
1507      *  <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br>
1508      *  <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br>
1509      *  <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br>
1510      *  <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br>
1511      *  For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
1512      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
1513      *  value, generally only useful for troubleshooting.<br>
1514      *  The per-application based SMS control checks sentIntent. If sentIntent
1515      *  is NULL the caller will be checked against all unknown applications,
1516      *  which cause smaller number of SMS to be sent in checking period.
1517      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
1518      *  broadcast when the message is delivered to the recipient.  The
1519      * @param messageUri optional URI of the message if it is already stored in the system
1520      * @param callingPkg the calling package name
1521      * @param persistMessage whether to save the sent message into SMS DB for a
1522      *  non-default SMS app.
1523      * @param priority Priority level of the message
1524      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
1525      *  ---------------------------------
1526      *  PRIORITY      | Level of Priority
1527      *  ---------------------------------
1528      *      '00'      |     Normal
1529      *      '01'      |     Interactive
1530      *      '10'      |     Urgent
1531      *      '11'      |     Emergency
1532      *  ----------------------------------
1533      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
1534      * @param expectMore is a boolean to indicate the sending messages through same link or not.
1535      * @param validityPeriod Validity Period of the message in mins.
1536      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
1537      *  Validity Period(Minimum) -> 5 mins
1538      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
1539      *  Any Other values included Negative considered as Invalid Validity Period of the message.
1540      * @param skipShortCodeCheck Skip check for short code type destination address.
1541      */
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, boolean skipShortCodeCheck)1542     public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent,
1543             PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage,
1544             int priority, boolean expectMore, int validityPeriod, boolean isForVvm,
1545             long messageId, boolean skipShortCodeCheck) {
1546         if (TextUtils.isEmpty(scAddr)) {
1547             scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg);
1548         }
1549 
1550         if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
1551             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1552             boolean isEmergency = tm.isEmergencyNumber(destAddr);
1553             DomainSelectionConnectionHolder holder = getDomainSelectionConnection(isEmergency);
1554 
1555             // If the DomainSelectionConnection is not available,
1556             // fallback to the legacy implementation.
1557             if (holder != null && holder.getConnection() != null) {
1558                 sendSmsUsingDomainSelection(holder,
1559                         new PendingRequest(PendingRequest.TYPE_TEXT, null, callingPkg,
1560                                 destAddr, scAddr, asArrayList(sentIntent),
1561                                 asArrayList(deliveryIntent), isForVvm, null, 0, asArrayList(text),
1562                                 messageUri, persistMessage, priority, expectMore, validityPeriod,
1563                                 messageId, skipShortCodeCheck),
1564                         "sendText");
1565                 return;
1566             }
1567         }
1568 
1569         if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport(destAddr)) {
1570             mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
1571                     messageUri, callingPkg, persistMessage, priority, false /*expectMore*/,
1572                     validityPeriod, isForVvm, messageId, skipShortCodeCheck);
1573         } else {
1574             if (isCdmaMo()) {
1575                 mCdmaDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
1576                         messageUri, callingPkg, persistMessage, priority, expectMore,
1577                         validityPeriod, isForVvm, messageId, skipShortCodeCheck);
1578             } else {
1579                 mGsmDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
1580                         messageUri, callingPkg, persistMessage, priority, expectMore,
1581                         validityPeriod, isForVvm, messageId, skipShortCodeCheck);
1582             }
1583         }
1584     }
1585 
1586     /**
1587      * Send a multi-part text based SMS.
1588      *
1589      * @param destAddr the address to send the message to
1590      * @param scAddr is the service center address or null to use
1591      *  the current default SMSC
1592      * @param parts an <code>ArrayList</code> of strings that, in order,
1593      *  comprise the original message
1594      * @param sentIntents if not null, an <code>ArrayList</code> of
1595      *  <code>PendingIntent</code>s (one for each message part) that is
1596      *  broadcast when the corresponding message part has been sent.
1597      *  The result code will be <code>Activity.RESULT_OK<code> for success,
1598      *  or one of these errors:<br>
1599      *  <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br>
1600      *  <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br>
1601      *  <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br>
1602      *  <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br>
1603      *  <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br>
1604      *  <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
1605      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
1606      *  <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
1607      *  <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br>
1608      *  <code>SmsManager.RESULT_NETWORK_REJECT</code><br>
1609      *  <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br>
1610      *  <code>SmsManager.RESULT_INVALID_STATE</code><br>
1611      *  <code>SmsManager.RESULT_NO_MEMORY</code><br>
1612      *  <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br>
1613      *  <code>SmsManager.RESULT_SYSTEM_ERROR</code><br>
1614      *  <code>SmsManager.RESULT_MODEM_ERROR</code><br>
1615      *  <code>SmsManager.RESULT_NETWORK_ERROR</code><br>
1616      *  <code>SmsManager.RESULT_ENCODING_ERROR</code><br>
1617      *  <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br>
1618      *  <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br>
1619      *  <code>SmsManager.RESULT_INTERNAL_ERROR</code><br>
1620      *  <code>SmsManager.RESULT_NO_RESOURCES</code><br>
1621      *  <code>SmsManager.RESULT_CANCELLED</code><br>
1622      *  <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br>
1623      *  <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br>
1624      *  <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
1625      *  <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br>
1626      *  <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
1627      *  <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
1628      *  <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br>
1629      *  <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br>
1630      *  <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br>
1631      *  <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
1632      *  <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
1633      *  <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br>
1634      *  <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br>
1635      *  <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br>
1636      *  <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br>
1637      *  <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
1638      *  <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br>
1639      *  <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br>
1640      *  <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br>
1641      *  <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
1642      *  <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br>
1643      *  <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br>
1644      *  <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br>
1645      *  <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
1646      *  <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br>
1647      *  <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br>
1648      *  <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
1649      *  <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br>
1650      *  <code>SmsManager.RESULT_RIL_CANCELLED</code><br>
1651      *  <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br>
1652      *  <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br>
1653      *  <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br>
1654      *  <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br>
1655      *  For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
1656      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
1657      *  value, generally only useful for troubleshooting.<br>
1658      *  The per-application based SMS control checks sentIntent. If sentIntent
1659      *  is NULL the caller will be checked against all unknown applications,
1660      *  which cause smaller number of SMS to be sent in checking period.
1661      * @param deliveryIntents if not null, an <code>ArrayList</code> of
1662      *  <code>PendingIntent</code>s (one for each message part) that is
1663      *  broadcast when the corresponding message part has been delivered
1664      *  to the recipient.  The raw pdu of the status report is in the
1665      * @param messageUri optional URI of the message if it is already stored in the system
1666      * @param callingPkg the calling package name
1667      * @param persistMessage whether to save the sent message into SMS DB for a
1668      *  non-default SMS app.
1669      * @param priority Priority level of the message
1670      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
1671      *  ---------------------------------
1672      *  PRIORITY      | Level of Priority
1673      *  ---------------------------------
1674      *      '00'      |     Normal
1675      *      '01'      |     Interactive
1676      *      '10'      |     Urgent
1677      *      '11'      |     Emergency
1678      *  ----------------------------------
1679      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
1680      * @param expectMore is a boolean to indicate the sending messages through same link or not.
1681      * @param validityPeriod Validity Period of the message in mins.
1682      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
1683      *  Validity Period(Minimum) -> 5 mins
1684      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
1685      *  Any Other values included Negative considered as Invalid Validity Period of the message.
1686      * @param messageId An id that uniquely identifies the message requested to be sent.
1687      *                 Used for logging and diagnostics purposes. The id may be 0.
1688      *
1689      */
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)1690     protected void sendMultipartText(String destAddr, String scAddr,
1691             ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
1692             ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
1693             boolean persistMessage, int priority, boolean expectMore, int validityPeriod,
1694             long messageId) {
1695         if (TextUtils.isEmpty(scAddr)) {
1696             scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg);
1697         }
1698 
1699         if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
1700             DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
1701 
1702             // If the DomainSelectionConnection is not available,
1703             // fallback to the legacy implementation.
1704             if (holder != null && holder.getConnection() != null) {
1705                 sendSmsUsingDomainSelection(holder,
1706                         new PendingRequest(PendingRequest.TYPE_MULTIPART_TEXT, null,
1707                                 callingPkg, destAddr, scAddr, sentIntents, deliveryIntents, false,
1708                                 null, 0, parts, messageUri, persistMessage, priority, expectMore,
1709                                 validityPeriod, messageId, false),
1710                         "sendMultipartText");
1711                 return;
1712             }
1713         }
1714 
1715         if (mImsSmsDispatcher.isAvailable()) {
1716             mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
1717                     deliveryIntents, messageUri, callingPkg, persistMessage, priority,
1718                     false /*expectMore*/, validityPeriod, messageId);
1719         } else {
1720             if (isCdmaMo()) {
1721                 mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
1722                         deliveryIntents, messageUri, callingPkg, persistMessage, priority,
1723                         expectMore, validityPeriod, messageId);
1724             } else {
1725                 mGsmDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
1726                         deliveryIntents, messageUri, callingPkg, persistMessage, priority,
1727                         expectMore, validityPeriod, messageId);
1728             }
1729         }
1730     }
1731 
1732     /**
1733      * Returns the premium SMS permission for the specified package. If the package has never
1734      * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN}
1735      * will be returned.
1736      * @param packageName the name of the package to query permission
1737      * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
1738      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
1739      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
1740      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
1741      */
getPremiumSmsPermission(String packageName)1742     public int getPremiumSmsPermission(String packageName) {
1743         return mUsageMonitor.getPremiumSmsPermission(packageName);
1744     }
1745 
1746     /**
1747      * Sets the premium SMS permission for the specified package and save the value asynchronously
1748      * to persistent storage.
1749      * @param packageName the name of the package to set permission
1750      * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
1751      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
1752      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
1753      */
setPremiumSmsPermission(String packageName, int permission)1754     public void setPremiumSmsPermission(String packageName, int permission) {
1755         mUsageMonitor.setPremiumSmsPermission(packageName, permission);
1756     }
1757 
getUsageMonitor()1758     public SmsUsageMonitor getUsageMonitor() {
1759         return mUsageMonitor;
1760     }
1761 
1762     /**
1763      * Handles the sms status report based on the format.
1764      *
1765      * @param format the format.
1766      * @param pdu the pdu of the report.
1767      */
handleSmsStatusReport(String format, byte[] pdu)1768     public void handleSmsStatusReport(String format, byte[] pdu) {
1769         int messageRef;
1770         SMSDispatcher.SmsTracker tracker;
1771         boolean handled = false;
1772         if (isCdmaFormat(format)) {
1773             com.android.internal.telephony.cdma.SmsMessage sms =
1774                     com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
1775             if (sms != null) {
1776                 boolean foundIn3GPPMap = false;
1777                 messageRef = sms.mMessageRef;
1778                 tracker = mDeliveryPendingMapFor3GPP2.get(messageRef);
1779                 if (tracker == null) {
1780                     // A tracker for this 3GPP2 report may be in the 3GPP map instead if the
1781                     // previously submitted SMS was 3GPP format.
1782                     // (i.e. Some carriers require that devices receive 3GPP2 SMS also even if IMS
1783                     // SMS format is 3GGP.)
1784                     tracker = mDeliveryPendingMapFor3GPP.get(messageRef);
1785                     if (tracker != null) {
1786                         foundIn3GPPMap = true;
1787                     }
1788                 }
1789                 if (tracker != null) {
1790                     // The status is composed of an error class (bits 25-24) and a status code
1791                     // (bits 23-16).
1792                     int errorClass = (sms.getStatus() >> 24) & 0x03;
1793                     if (errorClass != ERROR_TEMPORARY) {
1794                         // Update the message status (COMPLETE or FAILED)
1795                         tracker.updateSentMessageStatus(
1796                                 mContext,
1797                                 (errorClass == ERROR_NONE)
1798                                         ? Sms.STATUS_COMPLETE
1799                                         : Sms.STATUS_FAILED);
1800                         // No longer need to be kept.
1801                         if (foundIn3GPPMap) {
1802                             mDeliveryPendingMapFor3GPP.remove(messageRef);
1803                         } else {
1804                             mDeliveryPendingMapFor3GPP2.remove(messageRef);
1805                         }
1806                     }
1807                     handled = triggerDeliveryIntent(tracker, format, pdu);
1808                 }
1809             }
1810         } else {
1811             com.android.internal.telephony.gsm.SmsMessage sms =
1812                     com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
1813             if (sms != null) {
1814                 messageRef = sms.mMessageRef;
1815                 tracker = mDeliveryPendingMapFor3GPP.get(messageRef);
1816                 if (tracker != null) {
1817                     int tpStatus = sms.getStatus();
1818                     if (tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING) {
1819                         // Update the message status (COMPLETE or FAILED)
1820                         tracker.updateSentMessageStatus(mContext, tpStatus);
1821                         // No longer need to be kept.
1822                         mDeliveryPendingMapFor3GPP.remove(messageRef);
1823                     }
1824                     handled = triggerDeliveryIntent(tracker, format, pdu);
1825                 }
1826             }
1827         }
1828 
1829         if (!handled) {
1830             Rlog.e(TAG, "handleSmsStatusReport: can not handle the status report!");
1831         }
1832     }
1833 
triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu)1834     private boolean triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format,
1835                                           byte[] pdu) {
1836         PendingIntent intent = tracker.mDeliveryIntent;
1837         Intent fillIn = new Intent();
1838         fillIn.putExtra("pdu", pdu);
1839         fillIn.putExtra("format", format);
1840         try {
1841             intent.send(mContext, Activity.RESULT_OK, fillIn);
1842             return true;
1843         } catch (CanceledException ex) {
1844             return false;
1845         }
1846     }
1847 
1848     /**
1849      * Get InboundSmsHandler for the phone.
1850      */
getInboundSmsHandler(boolean is3gpp2)1851     public InboundSmsHandler getInboundSmsHandler(boolean is3gpp2) {
1852         if (is3gpp2) return mCdmaInboundSmsHandler;
1853         else return mGsmInboundSmsHandler;
1854     }
1855 
1856     public interface SmsInjectionCallback {
onSmsInjectedResult(int result)1857         void onSmsInjectedResult(int result);
1858     }
1859 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1860     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1861         mGsmInboundSmsHandler.dump(fd, pw, args);
1862         mCdmaInboundSmsHandler.dump(fd, pw, args);
1863         mGsmDispatcher.dump(fd, pw, args);
1864         mCdmaDispatcher.dump(fd, pw, args);
1865         mImsSmsDispatcher.dump(fd, pw, args);
1866     }
1867 
logd(String msg)1868     private void logd(String msg) {
1869         Rlog.d(TAG, msg);
1870     }
1871 
logi(String s)1872     private void logi(String s) {
1873         Rlog.i(TAG + " [" + mPhone.getPhoneId() + "]", s);
1874     }
1875 }
1876