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