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