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 android.Manifest.permission.SEND_SMS_NO_CONFIRMATION;
20 import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
21 import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
22 import static android.telephony.SmsManager.RESULT_ERROR_NONE;
23 import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
24 import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
25 import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
26 import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED;
27 import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED;
28 
29 import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PERIOD_NOT_SPECIFIED;
30 import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PRIORITY_NOT_SPECIFIED;
31 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
32 
33 import android.annotation.UserIdInt;
34 import android.app.Activity;
35 import android.app.AlertDialog;
36 import android.app.PendingIntent;
37 import android.app.PendingIntent.CanceledException;
38 import android.compat.annotation.UnsupportedAppUsage;
39 import android.content.ContentResolver;
40 import android.content.ContentValues;
41 import android.content.Context;
42 import android.content.DialogInterface;
43 import android.content.Intent;
44 import android.content.pm.ApplicationInfo;
45 import android.content.pm.PackageInfo;
46 import android.content.pm.PackageManager;
47 import android.content.res.Resources;
48 import android.database.ContentObserver;
49 import android.net.Uri;
50 import android.os.AsyncResult;
51 import android.os.Binder;
52 import android.os.Handler;
53 import android.os.Message;
54 import android.os.PersistableBundle;
55 import android.os.Process;
56 import android.os.UserHandle;
57 import android.provider.Settings;
58 import android.provider.Telephony;
59 import android.provider.Telephony.Sms;
60 import android.service.carrier.CarrierMessagingService;
61 import android.service.carrier.CarrierMessagingServiceWrapper;
62 import android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper;
63 import android.telephony.CarrierConfigManager;
64 import android.telephony.PhoneNumberUtils;
65 import android.telephony.ServiceState;
66 import android.telephony.SmsManager;
67 import android.telephony.TelephonyManager;
68 import android.text.Html;
69 import android.text.Spanned;
70 import android.text.TextUtils;
71 import android.util.EventLog;
72 import android.view.LayoutInflater;
73 import android.view.View;
74 import android.view.ViewGroup;
75 import android.view.WindowManager;
76 import android.widget.Button;
77 import android.widget.CheckBox;
78 import android.widget.CompoundButton;
79 import android.widget.TextView;
80 
81 import com.android.internal.R;
82 import com.android.internal.annotations.VisibleForTesting;
83 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
84 import com.android.internal.telephony.cdma.sms.UserData;
85 import com.android.internal.telephony.uicc.UiccCard;
86 import com.android.internal.telephony.uicc.UiccController;
87 import com.android.telephony.Rlog;
88 
89 import java.util.ArrayList;
90 import java.util.HashMap;
91 import java.util.List;
92 import java.util.Random;
93 import java.util.concurrent.atomic.AtomicBoolean;
94 import java.util.concurrent.atomic.AtomicInteger;
95 
96 public abstract class SMSDispatcher extends Handler {
97     static final String TAG = "SMSDispatcher";    // accessed from inner class
98     static final boolean DBG = false;
99     private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
100     private static final String MESSAGE_ID_EXTRA = "MessageId";
101     protected static final String MAP_KEY_PDU = "pdu";
102     protected static final String MAP_KEY_SMSC = "smsc";
103     protected static final String MAP_KEY_DEST_ADDR = "destAddr";
104     protected static final String MAP_KEY_SC_ADDR = "scAddr";
105     protected static final String MAP_KEY_DEST_PORT = "destPort";
106     protected static final String MAP_KEY_DATA = "data";
107     protected static final String MAP_KEY_TEXT = "text";
108 
109     private static final int PREMIUM_RULE_USE_SIM = 1;
110     private static final int PREMIUM_RULE_USE_NETWORK = 2;
111     private static final int PREMIUM_RULE_USE_BOTH = 3;
112     private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
113     private final SettingsObserver mSettingsObserver;
114 
115     /** SMS send complete. */
116     protected static final int EVENT_SEND_SMS_COMPLETE = 2;
117 
118     /** Retry sending a previously failed SMS message */
119     private static final int EVENT_SEND_RETRY = 3;
120 
121     /** Confirmation required for sending a large number of messages. */
122     private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
123 
124     /** Send the user confirmed SMS */
125     static final int EVENT_SEND_CONFIRMED_SMS = 5; // accessed from inner class
126 
127     /** Don't send SMS (user did not confirm). */
128     static final int EVENT_STOP_SENDING = 6; // accessed from inner class
129 
130     /** Don't send SMS for this app (User had already denied eariler.) */
131     static final int EVENT_SENDING_NOT_ALLOWED = 7;
132 
133     /** Confirmation required for third-party apps sending to an SMS short code. */
134     private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
135 
136     /** Confirmation required for third-party apps sending to an SMS short code. */
137     private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
138 
139     /** Handle status report from {@code CdmaInboundSmsHandler}. */
140     protected static final int EVENT_HANDLE_STATUS_REPORT = 10;
141 
142     // other
143     protected static final int EVENT_NEW_ICC_SMS = 14;
144     protected static final int EVENT_ICC_CHANGED = 15;
145     protected static final int EVENT_GET_IMS_SERVICE = 16;
146 
147 
148     @UnsupportedAppUsage
149     protected Phone mPhone;
150     @UnsupportedAppUsage
151     protected final Context mContext;
152     @UnsupportedAppUsage
153     protected final ContentResolver mResolver;
154     @UnsupportedAppUsage
155     protected final CommandsInterface mCi;
156     @UnsupportedAppUsage
157     protected final TelephonyManager mTelephonyManager;
158 
159     /** Maximum number of times to retry sending a failed SMS. */
160     private static final int MAX_SEND_RETRIES = 3;
161     /** Delay before next send attempt on a failed SMS, in milliseconds. */
162     private static final int SEND_RETRY_DELAY = 2000;
163     /** Message sending queue limit */
164     private static final int MO_MSG_QUEUE_LIMIT = 5;
165 
166     /**
167      * Message reference for a CONCATENATED_8_BIT_REFERENCE or
168      * CONCATENATED_16_BIT_REFERENCE message set.  Should be
169      * incremented for each set of concatenated messages.
170      * Static field shared by all dispatcher objects.
171      */
172     private static int sConcatenatedRef = new Random().nextInt(256);
173 
174     protected SmsDispatchersController mSmsDispatchersController;
175 
176     /** Number of outgoing SmsTrackers waiting for user confirmation. */
177     private int mPendingTrackerCount;
178 
179     /* Flags indicating whether the current device allows sms service */
180     protected boolean mSmsCapable = true;
181     protected boolean mSmsSendDisabled;
182 
183     @UnsupportedAppUsage
getNextConcatenatedRef()184     protected static int getNextConcatenatedRef() {
185         sConcatenatedRef += 1;
186         return sConcatenatedRef;
187     }
188 
189     /**
190      * Create a new SMS dispatcher.
191      * @param phone the Phone to use
192      */
SMSDispatcher(Phone phone, SmsDispatchersController smsDispatchersController)193     protected SMSDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) {
194         mPhone = phone;
195         mSmsDispatchersController = smsDispatchersController;
196         mContext = phone.getContext();
197         mResolver = mContext.getContentResolver();
198         mCi = phone.mCi;
199         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
200         mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
201         mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
202                 Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
203 
204         mSmsCapable = mContext.getResources().getBoolean(
205                 com.android.internal.R.bool.config_sms_capable);
206         mSmsSendDisabled = !mTelephonyManager.getSmsSendCapableForPhone(
207                 mPhone.getPhoneId(), mSmsCapable);
208         Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
209                 + " mSmsSendDisabled=" + mSmsSendDisabled);
210     }
211 
212     /**
213      * Observe the secure setting for updated premium sms determination rules
214      */
215     private static class SettingsObserver extends ContentObserver {
216         private final AtomicInteger mPremiumSmsRule;
217         private final Context mContext;
SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context)218         SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
219             super(handler);
220             mPremiumSmsRule = premiumSmsRule;
221             mContext = context;
222             onChange(false); // load initial value;
223         }
224 
225         @Override
onChange(boolean selfChange)226         public void onChange(boolean selfChange) {
227             mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
228                     Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
229         }
230     }
231 
232     /** Unregister for incoming SMS events. */
233     @UnsupportedAppUsage
dispose()234     public void dispose() {
235         mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
236     }
237 
238     /**
239      * The format of the message PDU in the associated broadcast intent.
240      * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
241      * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
242      *
243      * Note: All applications which handle incoming SMS messages by processing the
244      * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
245      * into the new methods in {@link android.telephony.SmsMessage} which take an
246      * extra format parameter. This is required in order to correctly decode the PDU on
247      * devices which require support for both 3GPP and 3GPP2 formats at the same time,
248      * such as CDMA/LTE devices and GSM/CDMA world phones.
249      *
250      * @return the format of the message PDU
251      */
getFormat()252     protected abstract String getFormat();
253 
254     /**
255      * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports
256      * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}.
257      * @param o the SmsMessage containing the status report
258      */
handleStatusReport(Object o)259     protected void handleStatusReport(Object o) {
260         Rlog.d(TAG, "handleStatusReport() called with no subclass.");
261     }
262 
263     /* TODO: Need to figure out how to keep track of status report routing in a
264      *       persistent manner. If the phone process restarts (reboot or crash),
265      *       we will lose this list and any status reports that come in after
266      *       will be dropped.
267      */
268     /** Sent messages awaiting a delivery status report. */
269     @UnsupportedAppUsage
270     protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
271 
272     /**
273      * Handles events coming from the phone stack. Overridden from handler.
274      *
275      * @param msg the message to handle
276      */
277     @Override
handleMessage(Message msg)278     public void handleMessage(Message msg) {
279         switch (msg.what) {
280         case EVENT_SEND_SMS_COMPLETE:
281             // An outbound SMS has been successfully transferred, or failed.
282             handleSendComplete((AsyncResult) msg.obj);
283             break;
284 
285         case EVENT_SEND_RETRY:
286             Rlog.d(TAG, "SMS retry..");
287             sendRetrySms((SmsTracker) msg.obj);
288             break;
289 
290         case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
291             handleReachSentLimit((SmsTracker[]) (msg.obj));
292             break;
293 
294         case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
295             handleConfirmShortCode(false, (SmsTracker[]) (msg.obj));
296             break;
297 
298         case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
299             handleConfirmShortCode(true, (SmsTracker[]) (msg.obj));
300             break;
301 
302         case EVENT_SEND_CONFIRMED_SMS:
303         {
304             SmsTracker[] trackers = (SmsTracker[]) msg.obj;
305             for (SmsTracker tracker : trackers) {
306                 sendSms(tracker);
307             }
308             mPendingTrackerCount--;
309             break;
310         }
311 
312         case EVENT_SENDING_NOT_ALLOWED:
313         {
314             SmsTracker[] trackers = (SmsTracker[]) msg.obj;
315             Rlog.d(TAG, "SMSDispatcher: EVENT_SENDING_NOT_ALLOWED - "
316                     + "sending SHORT_CODE_NEVER_ALLOWED error code.");
317             handleSmsTrackersFailure(
318                     trackers, RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, NO_ERROR_CODE);
319             break;
320         }
321 
322         case EVENT_STOP_SENDING:
323         {
324             SmsTracker[] trackers = (SmsTracker[]) msg.obj;
325             int error;
326             if (msg.arg1 == ConfirmDialogListener.SHORT_CODE_MSG) {
327                 if (msg.arg2 == ConfirmDialogListener.NEVER_ALLOW) {
328                     error = RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED;
329                     Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
330                             + "sending SHORT_CODE_NEVER_ALLOWED error code.");
331                 } else {
332                     error = RESULT_ERROR_SHORT_CODE_NOT_ALLOWED;
333                     Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
334                             + "sending SHORT_CODE_NOT_ALLOWED error code.");
335                 }
336             } else if (msg.arg1 == ConfirmDialogListener.RATE_LIMIT) {
337                 error = RESULT_ERROR_LIMIT_EXCEEDED;
338                 Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
339                         + "sending LIMIT_EXCEEDED error code.");
340             } else {
341                     error = SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING;
342                     Rlog.e(TAG, "SMSDispatcher: EVENT_STOP_SENDING - unexpected cases.");
343             }
344 
345             handleSmsTrackersFailure(trackers, error, NO_ERROR_CODE);
346             mPendingTrackerCount--;
347             break;
348         }
349 
350         case EVENT_HANDLE_STATUS_REPORT:
351             handleStatusReport(msg.obj);
352             break;
353 
354         default:
355             Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
356         }
357     }
358 
359     /**
360      * Use the carrier messaging service to send a data or text SMS.
361      */
362     protected abstract class SmsSender extends CarrierMessagingServiceWrapper {
363         protected final SmsTracker mTracker;
364         // Initialized in sendSmsByCarrierApp
365         protected volatile SmsSenderCallback mSenderCallback;
366 
SmsSender(SmsTracker tracker)367         protected SmsSender(SmsTracker tracker) {
368             mTracker = tracker;
369         }
370 
sendSmsByCarrierApp(String carrierPackageName, SmsSenderCallback senderCallback)371         public void sendSmsByCarrierApp(String carrierPackageName,
372                                         SmsSenderCallback senderCallback) {
373             mSenderCallback = senderCallback;
374             if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
375                 Rlog.e(TAG, "bindService() for carrier messaging service failed");
376                 mSenderCallback.onSendSmsComplete(
377                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
378                         0 /* messageRef */);
379             } else {
380                 Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
381             }
382         }
383     }
384 
385     /**
386      * Use the carrier messaging service to send a text SMS.
387      */
388     protected final class TextSmsSender extends SmsSender {
TextSmsSender(SmsTracker tracker)389         public TextSmsSender(SmsTracker tracker) {
390             super(tracker);
391         }
392 
393         @Override
onServiceReady()394         public void onServiceReady() {
395             HashMap<String, Object> map = mTracker.getData();
396             String text = (String) map.get(MAP_KEY_TEXT);
397 
398             if (text != null) {
399                 try {
400                     sendTextSms(
401                             text,
402                             getSubId(),
403                             mTracker.mDestAddress,
404                             (mTracker.mDeliveryIntent != null)
405                                     ? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
406                                     : 0,
407                             mSenderCallback);
408                 } catch (RuntimeException e) {
409                     Rlog.e(TAG, "Exception sending the SMS: " + e);
410                     mSenderCallback.onSendSmsComplete(
411                             CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
412                             0 /* messageRef */);
413                 }
414             } else {
415                 mSenderCallback.onSendSmsComplete(
416                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
417                         0 /* messageRef */);
418             }
419         }
420     }
421 
422     /**
423      * Use the carrier messaging service to send a data SMS.
424      */
425     protected final class DataSmsSender extends SmsSender {
DataSmsSender(SmsTracker tracker)426         public DataSmsSender(SmsTracker tracker) {
427             super(tracker);
428         }
429 
430         @Override
onServiceReady()431         public void onServiceReady() {
432             HashMap<String, Object> map = mTracker.getData();
433             byte[] data = (byte[]) map.get(MAP_KEY_DATA);
434             int destPort = (int) map.get(MAP_KEY_DEST_PORT);
435 
436             if (data != null) {
437                 try {
438                     sendDataSms(
439                             data,
440                             getSubId(),
441                             mTracker.mDestAddress,
442                             destPort,
443                             (mTracker.mDeliveryIntent != null)
444                                     ? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
445                                     : 0,
446                             mSenderCallback);
447                 } catch (RuntimeException e) {
448                     Rlog.e(TAG, "Exception sending the SMS: " + e
449                             + " id: " + mTracker.mMessageId);
450                     mSenderCallback.onSendSmsComplete(
451                             CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
452                             0 /* messageRef */);
453                 }
454             } else {
455                 mSenderCallback.onSendSmsComplete(
456                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
457                         0 /* messageRef */);
458             }
459         }
460     }
461 
462     /**
463      * Callback for TextSmsSender and DataSmsSender from the carrier messaging service.
464      * Once the result is ready, the carrier messaging service connection is disposed.
465      */
466     protected final class SmsSenderCallback extends
467             CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper {
468         private final SmsSender mSmsSender;
469 
SmsSenderCallback(SmsSender smsSender)470         public SmsSenderCallback(SmsSender smsSender) {
471             mSmsSender = smsSender;
472         }
473 
474         /**
475          * This method should be called only once.
476          */
477         @Override
onSendSmsComplete(int result, int messageRef)478         public void onSendSmsComplete(int result, int messageRef) {
479             checkCallerIsPhoneOrCarrierApp();
480             final long identity = Binder.clearCallingIdentity();
481             try {
482                 mSmsSender.disposeConnection(mContext);
483                 processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
484             } finally {
485                 Binder.restoreCallingIdentity(identity);
486             }
487         }
488 
489         @Override
onSendMultipartSmsComplete(int result, int[] messageRefs)490         public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
491             Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result);
492         }
493 
494         @Override
onFilterComplete(int result)495         public void onFilterComplete(int result) {
496             Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
497         }
498 
499         @Override
onSendMmsComplete(int result, byte[] sendConfPdu)500         public void onSendMmsComplete(int result, byte[] sendConfPdu) {
501             Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
502         }
503 
504         @Override
onDownloadMmsComplete(int result)505         public void onDownloadMmsComplete(int result) {
506             Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
507         }
508     }
509 
510     @UnsupportedAppUsage
processSendSmsResponse(SmsTracker tracker, int result, int messageRef)511     private void processSendSmsResponse(SmsTracker tracker, int result, int messageRef) {
512         if (tracker == null) {
513             Rlog.e(TAG, "processSendSmsResponse: null tracker");
514             return;
515         }
516 
517         SmsResponse smsResponse = new SmsResponse(messageRef, null /* ackPdu */, NO_ERROR_CODE);
518 
519         switch (result) {
520             case CarrierMessagingService.SEND_STATUS_OK:
521                 Rlog.d(TAG, "Sending SMS by IP succeeded."
522                         + " id: " + tracker.mMessageId);
523                 sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
524                                           new AsyncResult(tracker,
525                                                           smsResponse,
526                                                           null /* exception*/)));
527                 break;
528             case CarrierMessagingService.SEND_STATUS_ERROR:
529                 Rlog.d(TAG, "Sending SMS by IP failed."
530                         + " id: " + tracker.mMessageId);
531                 sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
532                         new AsyncResult(tracker, smsResponse,
533                                 new CommandException(CommandException.Error.GENERIC_FAILURE))));
534                 break;
535             case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
536                 Rlog.d(TAG, "Sending SMS by IP failed. Retry on carrier network."
537                         + " id: " + tracker.mMessageId);
538                 sendSubmitPdu(tracker);
539                 break;
540             default:
541                 Rlog.d(TAG, "Unknown result " + result + " Retry on carrier network."
542                         + " id: " + tracker.mMessageId);
543                 sendSubmitPdu(tracker);
544         }
545     }
546 
547     /**
548      * Use the carrier messaging service to send a multipart text SMS.
549      */
550     private final class MultipartSmsSender extends CarrierMessagingServiceWrapper {
551         private final List<String> mParts;
552         public final SmsTracker[] mTrackers;
553         // Initialized in sendSmsByCarrierApp
554         private volatile MultipartSmsSenderCallback mSenderCallback;
555 
MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers)556         MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) {
557             mParts = parts;
558             mTrackers = trackers;
559         }
560 
561         @UnsupportedAppUsage
sendSmsByCarrierApp(String carrierPackageName, MultipartSmsSenderCallback senderCallback)562         void sendSmsByCarrierApp(String carrierPackageName,
563                                  MultipartSmsSenderCallback senderCallback) {
564             mSenderCallback = senderCallback;
565             if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
566                 Rlog.e(TAG, "bindService() for carrier messaging service failed");
567                 mSenderCallback.onSendMultipartSmsComplete(
568                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
569                         null /* smsResponse */);
570             } else {
571                 Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
572             }
573         }
574 
575         @Override
onServiceReady()576         public void onServiceReady() {
577             boolean statusReportRequested = false;
578             for (SmsTracker tracker : mTrackers) {
579                 if (tracker.mDeliveryIntent != null) {
580                     statusReportRequested = true;
581                     break;
582                 }
583             }
584 
585             try {
586                 sendMultipartTextSms(
587                         mParts,
588                         getSubId(),
589                         mTrackers[0].mDestAddress,
590                         statusReportRequested
591                                 ? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
592                                 : 0,
593                         mSenderCallback);
594             } catch (RuntimeException e) {
595                 Rlog.e(TAG, "Exception sending the SMS: " + e);
596                 mSenderCallback.onSendMultipartSmsComplete(
597                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
598                         null /* smsResponse */);
599             }
600         }
601     }
602 
603     /**
604      * Callback for MultipartSmsSender from the carrier messaging service.
605      * Once the result is ready, the carrier messaging service connection is disposed.
606      */
607     private final class MultipartSmsSenderCallback extends CarrierMessagingCallbackWrapper {
608         private final MultipartSmsSender mSmsSender;
609 
MultipartSmsSenderCallback(MultipartSmsSender smsSender)610         MultipartSmsSenderCallback(MultipartSmsSender smsSender) {
611             mSmsSender = smsSender;
612         }
613 
614         @Override
onSendSmsComplete(int result, int messageRef)615         public void onSendSmsComplete(int result, int messageRef) {
616             Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result);
617         }
618 
619         /**
620          * This method should be called only once.
621          */
622         @Override
onSendMultipartSmsComplete(int result, int[] messageRefs)623         public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
624             mSmsSender.disposeConnection(mContext);
625 
626             if (mSmsSender.mTrackers == null) {
627                 Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers.");
628                 return;
629             }
630 
631             checkCallerIsPhoneOrCarrierApp();
632             final long identity = Binder.clearCallingIdentity();
633             try {
634                 for (int i = 0; i < mSmsSender.mTrackers.length; i++) {
635                     int messageRef = 0;
636                     if (messageRefs != null && messageRefs.length > i) {
637                         messageRef = messageRefs[i];
638                     }
639                     processSendSmsResponse(mSmsSender.mTrackers[i], result, messageRef);
640                 }
641             } finally {
642                 Binder.restoreCallingIdentity(identity);
643             }
644         }
645 
646         @Override
onFilterComplete(int result)647         public void onFilterComplete(int result) {
648             Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
649         }
650 
651         @Override
onSendMmsComplete(int result, byte[] sendConfPdu)652         public void onSendMmsComplete(int result, byte[] sendConfPdu) {
653             Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
654         }
655 
656         @Override
onDownloadMmsComplete(int result)657         public void onDownloadMmsComplete(int result) {
658             Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
659         }
660     }
661 
662     /** Send a single SMS PDU. */
663     @UnsupportedAppUsage
sendSubmitPdu(SmsTracker tracker)664     private void sendSubmitPdu(SmsTracker tracker) {
665         sendSubmitPdu(new SmsTracker[] {tracker});
666     }
667 
668     /** Send a multi-part SMS PDU. Usually just calls {@link sendRawPdu}. */
sendSubmitPdu(SmsTracker[] trackers)669     private void sendSubmitPdu(SmsTracker[] trackers) {
670         if (shouldBlockSmsForEcbm()) {
671             Rlog.d(TAG, "Block SMS in Emergency Callback mode");
672             handleSmsTrackersFailure(trackers, SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY,
673                     NO_ERROR_CODE);
674         } else {
675             sendRawPdu(trackers);
676         }
677     }
678 
679     /**
680      * @return true if MO SMS should be blocked for Emergency Callback Mode.
681      */
shouldBlockSmsForEcbm()682     protected abstract boolean shouldBlockSmsForEcbm();
683 
684     /**
685      * Called when SMS send completes. Broadcasts a sentIntent on success.
686      * On failure, either sets up retries or broadcasts a sentIntent with
687      * the failure in the result code.
688      *
689      * @param ar AsyncResult passed into the message handler.  ar.result should
690      *           an SmsResponse instance if send was successful.  ar.userObj
691      *           should be an SmsTracker instance.
692      */
handleSendComplete(AsyncResult ar)693     protected void handleSendComplete(AsyncResult ar) {
694         SmsTracker tracker = (SmsTracker) ar.userObj;
695         PendingIntent sentIntent = tracker.mSentIntent;
696 
697         if (ar.result != null) {
698             tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
699         } else {
700             Rlog.d(TAG, "SmsResponse was null");
701         }
702 
703         if (ar.exception == null) {
704             if (DBG) {
705                 Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent
706                         + " id: " + tracker.mMessageId);
707             }
708 
709             if (tracker.mDeliveryIntent != null) {
710                 // Expecting a status report.  Add it to the list.
711                 deliveryPendingList.add(tracker);
712             }
713             tracker.onSent(mContext);
714             mPhone.notifySmsSent(tracker.mDestAddress);
715         } else {
716             if (DBG) {
717                 Rlog.d(TAG, "SMS send failed"
718                         + " id: " + tracker.mMessageId);
719             }
720 
721             int ss = mPhone.getServiceState().getState();
722 
723             if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
724                 // This is retry after failure over IMS but voice is not available.
725                 // Set retry to max allowed, so no retry is sent and
726                 //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.
727                 tracker.mRetryCount = MAX_SEND_RETRIES;
728 
729                 Rlog.d(TAG, "handleSendComplete: Skipping retry: "
730                         + " isIms()=" + isIms()
731                         + " mRetryCount=" + tracker.mRetryCount
732                         + " mImsRetry=" + tracker.mImsRetry
733                         + " mMessageRef=" + tracker.mMessageRef
734                         + " SS= " + mPhone.getServiceState().getState()
735                         + " id=" + tracker.mMessageId);
736             }
737 
738             // if sms over IMS is not supported on data and voice is not available...
739             if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
740                 tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE);
741             } else if ((((CommandException)(ar.exception)).getCommandError()
742                     == CommandException.Error.SMS_FAIL_RETRY) &&
743                    tracker.mRetryCount < MAX_SEND_RETRIES) {
744                 // Retry after a delay if needed.
745                 // TODO: According to TS 23.040, 9.2.3.6, we should resend
746                 //       with the same TP-MR as the failed message, and
747                 //       TP-RD set to 1.  However, we don't have a means of
748                 //       knowing the MR for the failed message (EF_SMSstatus
749                 //       may or may not have the MR corresponding to this
750                 //       message, depending on the failure).  Also, in some
751                 //       implementations this retry is handled by the baseband.
752                 tracker.mRetryCount++;
753                 Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
754                 sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
755             } else {
756                 int errorCode = NO_ERROR_CODE;
757                 if (ar.result != null) {
758                     errorCode = ((SmsResponse)ar.result).mErrorCode;
759                 }
760                 int error = rilErrorToSmsManagerResult(((CommandException) (ar.exception))
761                         .getCommandError());
762                 tracker.onFailed(mContext, error, errorCode);
763             }
764         }
765     }
766 
rilErrorToSmsManagerResult(CommandException.Error rilError)767     private static int rilErrorToSmsManagerResult(CommandException.Error rilError) {
768         switch (rilError) {
769             case RADIO_NOT_AVAILABLE:
770                 return SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE;
771             case SMS_FAIL_RETRY:
772                 return SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY;
773             case NETWORK_REJECT:
774                 return SmsManager.RESULT_RIL_NETWORK_REJECT;
775             case INVALID_STATE:
776                 return SmsManager.RESULT_RIL_INVALID_STATE;
777             case INVALID_ARGUMENTS:
778                 return SmsManager.RESULT_RIL_INVALID_ARGUMENTS;
779             case NO_MEMORY:
780                 return SmsManager.RESULT_RIL_NO_MEMORY;
781             case REQUEST_RATE_LIMITED:
782                 return SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED;
783             case INVALID_SMS_FORMAT:
784                 return SmsManager.RESULT_RIL_INVALID_SMS_FORMAT;
785             case SYSTEM_ERR:
786                 return SmsManager.RESULT_RIL_SYSTEM_ERR;
787             case ENCODING_ERR:
788                 return SmsManager.RESULT_RIL_ENCODING_ERR;
789             case MODEM_ERR:
790                 return SmsManager.RESULT_RIL_MODEM_ERR;
791             case NETWORK_ERR:
792                 return SmsManager.RESULT_RIL_NETWORK_ERR;
793             case INTERNAL_ERR:
794                 return SmsManager.RESULT_RIL_INTERNAL_ERR;
795             case REQUEST_NOT_SUPPORTED:
796                 return SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED;
797             case INVALID_MODEM_STATE:
798                 return SmsManager.RESULT_RIL_INVALID_MODEM_STATE;
799             case NETWORK_NOT_READY:
800                 return SmsManager.RESULT_RIL_NETWORK_NOT_READY;
801             case OPERATION_NOT_ALLOWED:
802                 return SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED;
803             case NO_RESOURCES:
804                 return SmsManager.RESULT_RIL_NO_RESOURCES;
805             case REQUEST_CANCELLED:
806                 return SmsManager.RESULT_RIL_CANCELLED;
807             case SIM_ABSENT:
808                 return SmsManager.RESULT_RIL_SIM_ABSENT;
809             case FDN_CHECK_FAILURE:
810                 return SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
811             default:
812                 return RESULT_ERROR_GENERIC_FAILURE;
813         }
814     }
815 
816     /**
817      * Handles outbound message when the phone is not in service.
818      *
819      * @param ss     Current service state.  Valid values are:
820      *                  OUT_OF_SERVICE
821      *                  EMERGENCY_ONLY
822      *                  POWER_OFF
823      * @param sentIntent the PendingIntent to send the error to
824      */
handleNotInService(int ss, PendingIntent sentIntent)825     protected static void handleNotInService(int ss, PendingIntent sentIntent) {
826         if (sentIntent != null) {
827             try {
828                 if (ss == ServiceState.STATE_POWER_OFF) {
829                     sentIntent.send(RESULT_ERROR_RADIO_OFF);
830                 } else {
831                     sentIntent.send(RESULT_ERROR_NO_SERVICE);
832                 }
833             } catch (CanceledException ex) {
834                 Rlog.e(TAG, "Failed to send result");
835             }
836         }
837     }
838 
839     /**
840      * @param ss service state
841      * @return The result error based on input service state for not in service error
842      */
getNotInServiceError(int ss)843     protected static int getNotInServiceError(int ss) {
844         if (ss == ServiceState.STATE_POWER_OFF) {
845             return RESULT_ERROR_RADIO_OFF;
846         }
847         return RESULT_ERROR_NO_SERVICE;
848     }
849 
850     /**
851      * Send a data based SMS to a specific application port.
852      *
853      * @param callingPackage the package name of the calling app
854      * @param destAddr the address to send the message to
855      * @param scAddr is the service center address or null to use
856      *  the current default SMSC
857      * @param destPort the port to deliver the message to
858      * @param data the body of the message to send
859      * @param sentIntent if not NULL this <code>PendingIntent</code> is
860      *  broadcast when the message is successfully sent, or failed.
861      *  The result code will be <code>Activity.RESULT_OK<code> for success,
862      *  or one of these errors:<br>
863      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
864      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
865      *  <code>RESULT_ERROR_NULL_PDU</code><br>
866      *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
867      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
868      *  the extra "errorCode" containing a radio technology specific value,
869      *  generally only useful for troubleshooting.<br>
870      *  The per-application based SMS control checks sentIntent. If sentIntent
871      *  is NULL the caller will be checked against all unknown applications,
872      *  which cause smaller number of SMS to be sent in checking period.
873      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
874      *  broadcast when the message is delivered to the recipient.  The
875      *  raw pdu of the status report is in the extended data ("pdu").
876      */
877     @UnsupportedAppUsage
sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)878     protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort,
879             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) {
880         SmsMessageBase.SubmitPduBase pdu = getSubmitPdu(
881                 scAddr, destAddr, destPort, data, (deliveryIntent != null));
882         if (pdu != null) {
883             HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
884             SmsTracker tracker = getSmsTracker(callingPackage, map, sentIntent, deliveryIntent,
885                     getFormat(), null /*messageUri*/, false /*expectMore*/,
886                     null /*fullMessageText*/, false /*isText*/,
887                     true /*persistMessage*/, isForVvm, 0L /* messageId */);
888 
889             if (!sendSmsByCarrierApp(true /* isDataSms */, tracker)) {
890                 sendSubmitPdu(tracker);
891             }
892         } else {
893             Rlog.e(TAG, "SMSDispatcher.sendData(): getSubmitPdu() returned null");
894             triggerSentIntentForFailure(sentIntent);
895         }
896     }
897 
898     /**
899      * Send a text based SMS.
900      *  @param destAddr the address to send the message to
901      * @param scAddr is the service center address or null to use
902      *  the current default SMSC
903      * @param text the body of the message to send
904      * @param sentIntent if not NULL this <code>PendingIntent</code> is
905      *  broadcast when the message is successfully sent, or failed.
906      *  The result code will be <code>Activity.RESULT_OK<code> for success,
907      *  or one of these errors:<br>
908      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
909      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
910      *  <code>RESULT_ERROR_NULL_PDU</code><br>
911      *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
912      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
913      *  the extra "errorCode" containing a radio technology specific value,
914      *  generally only useful for troubleshooting.<br>
915      *  The per-application based SMS control checks sentIntent. If sentIntent
916      *  is NULL the caller will be checked against all unknown applications,
917      *  which cause smaller number of SMS to be sent in checking period.
918      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
919      *  broadcast when the message is delivered to the recipient.  The
920      * @param messageUri optional URI of the message if it is already stored in the system
921      * @param callingPkg the calling package name
922      * @param persistMessage whether to save the sent message into SMS DB for a
923      *   non-default SMS app.
924      *
925      * @param priority Priority level of the message
926      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
927      *  ---------------------------------
928      *  PRIORITY      | Level of Priority
929      *  ---------------------------------
930      *      '00'      |     Normal
931      *      '01'      |     Interactive
932      *      '10'      |     Urgent
933      *      '11'      |     Emergency
934      *  ----------------------------------
935      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
936      * @param expectMore is a boolean to indicate the sending messages through same link or not.
937      * @param validityPeriod Validity Period of the message in mins.
938      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
939      *  Validity Period(Minimum) -> 5 mins
940      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
941      *  Any Other values included Negative considered as Invalid Validity Period of the message.
942      * @param messageId An id that uniquely identifies the message requested to be sent.
943      *                 Used for logging and diagnostics purposes. The id may be NULL.
944      */
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)945     public void sendText(String destAddr, String scAddr, String text,
946                          PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri,
947                          String callingPkg, boolean persistMessage, int priority,
948                          boolean expectMore, int validityPeriod, boolean isForVvm,
949                          long messageId) {
950         Rlog.d(TAG, "sendText id: " + messageId);
951         SmsMessageBase.SubmitPduBase pdu = getSubmitPdu(
952                 scAddr, destAddr, text, (deliveryIntent != null), null, priority, validityPeriod);
953         if (pdu != null) {
954             HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
955             SmsTracker tracker = getSmsTracker(callingPkg, map, sentIntent, deliveryIntent,
956                     getFormat(), messageUri, expectMore, text, true /*isText*/,
957                     persistMessage, priority, validityPeriod, isForVvm, messageId);
958 
959             if (!sendSmsByCarrierApp(false /* isDataSms */, tracker)) {
960                 sendSubmitPdu(tracker);
961             }
962         } else {
963             Rlog.e(TAG, "SmsDispatcher.sendText(): getSubmitPdu() returned null" + " id: "
964                     + messageId);
965             triggerSentIntentForFailure(sentIntent);
966         }
967     }
968 
triggerSentIntentForFailure(PendingIntent sentIntent)969     private void triggerSentIntentForFailure(PendingIntent sentIntent) {
970         if (sentIntent != null) {
971             try {
972                 sentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
973             } catch (CanceledException ex) {
974                 Rlog.e(TAG, "Intent has been canceled!");
975             }
976         }
977     }
978 
triggerSentIntentForFailure(List<PendingIntent> sentIntents)979     private void triggerSentIntentForFailure(List<PendingIntent> sentIntents) {
980         if (sentIntents == null) {
981             return;
982         }
983 
984         for (PendingIntent sentIntent : sentIntents) {
985             triggerSentIntentForFailure(sentIntent);
986         }
987     }
988 
sendSmsByCarrierApp(boolean isDataSms, SmsTracker tracker )989     private boolean sendSmsByCarrierApp(boolean isDataSms, SmsTracker tracker ) {
990         String carrierPackage = getCarrierAppPackageName();
991         if (carrierPackage != null) {
992             Rlog.d(TAG, "Found carrier package.");
993             SmsSender smsSender;
994             if (isDataSms) {
995                 smsSender = new DataSmsSender(tracker);
996             } else {
997                 smsSender = new TextSmsSender(tracker);
998             }
999             smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
1000             return true;
1001         }
1002 
1003         return false;
1004     }
1005 
getSubmitPdu(String scAddr, String destAddr, String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, int validityPeriod)1006     protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr,
1007             String message, boolean statusReportRequested, SmsHeader smsHeader,
1008             int priority, int validityPeriod);
1009 
getSubmitPdu(String scAddr, String destAddr, int destPort, byte[] message, boolean statusReportRequested)1010     protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr,
1011             int destPort, byte[] message, boolean statusReportRequested);
1012 
1013     /**
1014      * Calculate the number of septets needed to encode the message. This function should only be
1015      * called for individual segments of multipart message.
1016      *
1017      * @param messageBody the message to encode
1018      * @param use7bitOnly ignore (but still count) illegal characters if true
1019      * @return TextEncodingDetails
1020      */
1021     @UnsupportedAppUsage
calculateLength(CharSequence messageBody, boolean use7bitOnly)1022     protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
1023             boolean use7bitOnly);
1024 
1025     /**
1026      * Send a multi-part text based SMS.
1027      *  @param destAddr the address to send the message to
1028      * @param scAddr is the service center address or null to use
1029      *   the current default SMSC
1030      * @param parts an <code>ArrayList</code> of strings that, in order,
1031      *   comprise the original message
1032      * @param sentIntents if not null, an <code>ArrayList</code> of
1033      *   <code>PendingIntent</code>s (one for each message part) that is
1034      *   broadcast when the corresponding message part has been sent.
1035      *   The result code will be <code>Activity.RESULT_OK<code> for success,
1036      *   or one of these errors:
1037      *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
1038      *   <code>RESULT_ERROR_RADIO_OFF</code>
1039      *   <code>RESULT_ERROR_NULL_PDU</code>
1040      *   <code>RESULT_ERROR_NO_SERVICE</code>.
1041      *  The per-application based SMS control checks sentIntent. If sentIntent
1042      *  is NULL the caller will be checked against all unknown applications,
1043      *  which cause smaller number of SMS to be sent in checking period.
1044      * @param deliveryIntents if not null, an <code>ArrayList</code> of
1045      *   <code>PendingIntent</code>s (one for each message part) that is
1046      *   broadcast when the corresponding message part has been delivered
1047      *   to the recipient.  The raw pdu of the status report is in the
1048      * @param messageUri optional URI of the message if it is already stored in the system
1049      * @param callingPkg the calling package name
1050      * @param persistMessage whether to save the sent message into SMS DB for a
1051      *   non-default SMS app.
1052      * @param priority Priority level of the message
1053      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
1054      *  ---------------------------------
1055      *  PRIORITY      | Level of Priority
1056      *  ---------------------------------
1057      *      '00'      |     Normal
1058      *      '01'      |     Interactive
1059      *      '10'      |     Urgent
1060      *      '11'      |     Emergency
1061      *  ----------------------------------
1062      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
1063      * @param expectMore is a boolean to indicate the sending messages through same link or not.
1064      * @param validityPeriod Validity Period of the message in mins.
1065      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
1066      *  Validity Period(Minimum) -> 5 mins
1067      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
1068      *  Any Other values included Negative considered as Invalid Validity Period of the message.
1069      */
1070     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
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)1071     public void sendMultipartText(String destAddr, String scAddr,
1072             ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
1073             ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
1074             boolean persistMessage, int priority, boolean expectMore, int validityPeriod,
1075             long messageId) {
1076         final String fullMessageText = getMultipartMessageText(parts);
1077         int refNumber = getNextConcatenatedRef() & 0x00FF;
1078         int encoding = SmsConstants.ENCODING_UNKNOWN;
1079         int msgCount = parts.size();
1080         if (msgCount < 1) {
1081             triggerSentIntentForFailure(sentIntents);
1082             return;
1083         }
1084 
1085         TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
1086         for (int i = 0; i < msgCount; i++) {
1087             TextEncodingDetails details = calculateLength(parts.get(i), false);
1088             if (encoding != details.codeUnitSize
1089                     && (encoding == SmsConstants.ENCODING_UNKNOWN
1090                             || encoding == SmsConstants.ENCODING_7BIT)) {
1091                 encoding = details.codeUnitSize;
1092             }
1093             encodingForParts[i] = details;
1094         }
1095 
1096         SmsTracker[] trackers = new SmsTracker[msgCount];
1097 
1098         // States to track at the message level (for all parts)
1099         final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
1100         final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
1101 
1102         for (int i = 0; i < msgCount; i++) {
1103             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
1104             concatRef.refNumber = refNumber;
1105             concatRef.seqNumber = i + 1;  // 1-based sequence
1106             concatRef.msgCount = msgCount;
1107             // TODO: We currently set this to true since our messaging app will never
1108             // send more than 255 parts (it converts the message to MMS well before that).
1109             // However, we should support 3rd party messaging apps that might need 16-bit
1110             // references
1111             // Note:  It's not sufficient to just flip this bit to true; it will have
1112             // ripple effects (several calculations assume 8-bit ref).
1113             concatRef.isEightBits = true;
1114             SmsHeader smsHeader = new SmsHeader();
1115             smsHeader.concatRef = concatRef;
1116 
1117             // Set the national language tables for 3GPP 7-bit encoding, if enabled.
1118             if (encoding == SmsConstants.ENCODING_7BIT) {
1119                 smsHeader.languageTable = encodingForParts[i].languageTable;
1120                 smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
1121             }
1122 
1123             PendingIntent sentIntent = null;
1124             if (sentIntents != null && sentIntents.size() > i) {
1125                 sentIntent = sentIntents.get(i);
1126             }
1127 
1128             PendingIntent deliveryIntent = null;
1129             if (deliveryIntents != null && deliveryIntents.size() > i) {
1130                 deliveryIntent = deliveryIntents.get(i);
1131             }
1132 
1133             trackers[i] =
1134                 getNewSubmitPduTracker(callingPkg, destAddr, scAddr, parts.get(i), smsHeader,
1135                         encoding, sentIntent, deliveryIntent, (i == (msgCount - 1)),
1136                         unsentPartCount, anyPartFailed, messageUri,
1137                         fullMessageText, priority, expectMore, validityPeriod, messageId);
1138             if (trackers[i] == null) {
1139                 triggerSentIntentForFailure(sentIntents);
1140                 return;
1141             }
1142             trackers[i].mPersistMessage = persistMessage;
1143         }
1144 
1145         String carrierPackage = getCarrierAppPackageName();
1146         if (carrierPackage != null) {
1147             Rlog.d(TAG, "Found carrier package."
1148                     + " id: " + getMultiTrackermessageId(trackers));
1149             MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
1150             smsSender.sendSmsByCarrierApp(carrierPackage,
1151                     new MultipartSmsSenderCallback(smsSender));
1152         } else {
1153             Rlog.v(TAG, "No carrier package."
1154                     + " id: " + getMultiTrackermessageId(trackers));
1155             sendSubmitPdu(trackers);
1156         }
1157     }
1158 
getMultiTrackermessageId(SmsTracker[] trackers)1159     private long getMultiTrackermessageId(SmsTracker[] trackers) {
1160         if (trackers.length == 0) {
1161             return 0L;
1162         }
1163         return trackers[0].mMessageId;
1164     }
1165 
1166     /**
1167      * Create a new SubmitPdu and return the SMS tracker.
1168      */
getNewSubmitPduTracker(String callingPackage, String destinationAddress, String scAddress, String message, SmsHeader smsHeader, int encoding, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, String fullMessageText, int priority, boolean expectMore, int validityPeriod, long messageId)1169     private SmsTracker getNewSubmitPduTracker(String callingPackage, String destinationAddress,
1170             String scAddress, String message, SmsHeader smsHeader, int encoding,
1171             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
1172             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
1173             String fullMessageText, int priority, boolean expectMore, int validityPeriod,
1174             long messageId) {
1175         if (isCdmaMo()) {
1176             UserData uData = new UserData();
1177             uData.payloadStr = message;
1178             uData.userDataHeader = smsHeader;
1179             if (encoding == SmsConstants.ENCODING_7BIT) {
1180                 uData.msgEncoding = isAscii7bitSupportedForLongMessage()
1181                         ? UserData.ENCODING_7BIT_ASCII : UserData.ENCODING_GSM_7BIT_ALPHABET;
1182                 Rlog.d(TAG, "Message encoding for proper 7 bit: " + uData.msgEncoding);
1183             } else { // assume UTF-16
1184                 uData.msgEncoding = UserData.ENCODING_UNICODE_16;
1185             }
1186             uData.msgEncodingSet = true;
1187 
1188             /* By setting the statusReportRequested bit only for the
1189              * last message fragment, this will result in only one
1190              * callback to the sender when that last fragment delivery
1191              * has been acknowledged. */
1192             //TODO FIX
1193             SmsMessageBase.SubmitPduBase submitPdu =
1194                     com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(destinationAddress,
1195                             uData, (deliveryIntent != null) && lastPart, priority);
1196 
1197             if (submitPdu != null) {
1198                 HashMap map = getSmsTrackerMap(destinationAddress, scAddress,
1199                         message, submitPdu);
1200                 return getSmsTracker(callingPackage, map, sentIntent, deliveryIntent,
1201                         getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader,
1202                         (!lastPart || expectMore), fullMessageText, true /*isText*/,
1203                         true /*persistMessage*/, priority, validityPeriod, false /* isForVvm */,
1204                         messageId);
1205             } else {
1206                 Rlog.e(TAG, "CdmaSMSDispatcher.getNewSubmitPduTracker(): getSubmitPdu() returned "
1207                         + "null" + " id: " + messageId);
1208                 return null;
1209             }
1210         } else {
1211             SmsMessageBase.SubmitPduBase pdu =
1212                     com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
1213                             destinationAddress, message, deliveryIntent != null,
1214                             SmsHeader.toByteArray(smsHeader), encoding, smsHeader.languageTable,
1215                             smsHeader.languageShiftTable, validityPeriod);
1216             if (pdu != null) {
1217                 HashMap map =  getSmsTrackerMap(destinationAddress, scAddress,
1218                         message, pdu);
1219                 return getSmsTracker(callingPackage, map, sentIntent,
1220                         deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri,
1221                         smsHeader, (!lastPart || expectMore), fullMessageText, true /*isText*/,
1222                         false /*persistMessage*/, priority, validityPeriod, false /* isForVvm */,
1223                         messageId);
1224             } else {
1225                 Rlog.e(TAG, "GsmSMSDispatcher.getNewSubmitPduTracker(): getSubmitPdu() returned "
1226                         + "null" + " id: " + messageId);
1227                 return null;
1228             }
1229         }
1230     }
1231 
1232     /**
1233      * Send a single or a multi-part SMS
1234      * @param trackers each tracker will contain:
1235      * -smsc the SMSC to send the message through, or NULL for the
1236      *  default SMSC
1237      * -pdu the raw PDU to send
1238      * -sentIntent if not NULL this <code>Intent</code> is
1239      *  broadcast when the message is successfully sent, or failed.
1240      *  The result code will be <code>Activity.RESULT_OK<code> for success,
1241      *  or one of these errors:
1242      *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
1243      *  <code>RESULT_ERROR_RADIO_OFF</code>
1244      *  <code>RESULT_ERROR_NULL_PDU</code>
1245      *  <code>RESULT_ERROR_NO_SERVICE</code>.
1246      *  The per-application based SMS control checks sentIntent. If sentIntent
1247      *  is NULL the caller will be checked against all unknown applications,
1248      *  which cause smaller number of SMS to be sent in checking period.
1249      * -deliveryIntent if not NULL this <code>Intent</code> is
1250      *  broadcast when the message is delivered to the recipient.  The
1251      *  raw pdu of the status report is in the extended data ("pdu").
1252      * -param destAddr the destination phone number (for short code confirmation)
1253      */
1254     @VisibleForTesting
sendRawPdu(SmsTracker[] trackers)1255     public void sendRawPdu(SmsTracker[] trackers) {
1256         int error = RESULT_ERROR_NONE;
1257         PackageInfo appInfo = null;
1258         if (mSmsSendDisabled) {
1259             Rlog.e(TAG, "Device does not support sending sms.");
1260             error = RESULT_ERROR_NO_SERVICE;
1261         } else {
1262             for (SmsTracker tracker : trackers) {
1263                 if (tracker.getData().get(MAP_KEY_PDU) == null) {
1264                     Rlog.e(TAG, "Empty PDU");
1265                     error = RESULT_ERROR_NULL_PDU;
1266                     break;
1267                 }
1268             }
1269 
1270             if (error == RESULT_ERROR_NONE) {
1271                 UserHandle userHandle = UserHandle.of(trackers[0].mUserId);
1272                 PackageManager pm = mContext.createContextAsUser(userHandle, 0).getPackageManager();
1273 
1274                 try {
1275                     // Get package info via packagemanager
1276                     appInfo =
1277                             pm.getPackageInfo(
1278                                     trackers[0].getAppPackageName(),
1279                                     PackageManager.GET_SIGNATURES);
1280                 } catch (PackageManager.NameNotFoundException e) {
1281                     Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS"
1282                             + " id: " + getMultiTrackermessageId(trackers));
1283                     error = RESULT_ERROR_GENERIC_FAILURE;
1284                 }
1285             }
1286         }
1287 
1288         if (error != RESULT_ERROR_NONE) {
1289             handleSmsTrackersFailure(trackers, error, NO_ERROR_CODE);
1290             return;
1291         }
1292 
1293         // checkDestination() returns true if the destination is not a premium short code or the
1294         // sending app is approved to send to short codes. Otherwise, a message is sent to our
1295         // handler with the SmsTracker to request user confirmation before sending.
1296         if (checkDestination(trackers)) {
1297             // check for excessive outgoing SMS usage by this app
1298             if (!mSmsDispatchersController
1299                     .getUsageMonitor()
1300                     .check(appInfo.packageName, trackers.length)) {
1301                 sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, trackers));
1302                 return;
1303             }
1304 
1305             for (SmsTracker tracker : trackers) {
1306                 sendSms(tracker);
1307             }
1308         }
1309 
1310         if (PhoneNumberUtils.isLocalEmergencyNumber(mContext, trackers[0].mDestAddress)) {
1311             new AsyncEmergencyContactNotifier(mContext).execute();
1312         }
1313     }
1314 
1315     /**
1316      * Check if destination is a potential premium short code and sender is not pre-approved to send
1317      * to short codes.
1318      *
1319      * @param trackers the trackers for a single or a multi-part SMS to send
1320      * @return true if the destination is approved; false if user confirmation event was sent
1321      */
checkDestination(SmsTracker[] trackers)1322     boolean checkDestination(SmsTracker[] trackers) {
1323         if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION)
1324                 == PackageManager.PERMISSION_GRANTED || trackers[0].mIsForVvm) {
1325             return true;            // app is pre-approved to send to short codes
1326         } else {
1327             int rule = mPremiumSmsRule.get();
1328             int smsCategory = SmsManager.SMS_CATEGORY_NOT_SHORT_CODE;
1329             if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
1330                 String simCountryIso =
1331                         mTelephonyManager.getSimCountryIsoForPhone(mPhone.getPhoneId());
1332                 if (simCountryIso == null || simCountryIso.length() != 2) {
1333                     Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso"
1334                             + " id: " + getMultiTrackermessageId(trackers));
1335                     simCountryIso =
1336                             mTelephonyManager.getNetworkCountryIso(mPhone.getPhoneId());
1337                 }
1338 
1339                 smsCategory =
1340                         mSmsDispatchersController
1341                                 .getUsageMonitor()
1342                                 .checkDestination(trackers[0].mDestAddress, simCountryIso);
1343             }
1344             if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
1345                 String networkCountryIso =
1346                         mTelephonyManager.getNetworkCountryIso(mPhone.getPhoneId());
1347                 if (networkCountryIso == null || networkCountryIso.length() != 2) {
1348                     Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso"
1349                             + " id: " + getMultiTrackermessageId(trackers));
1350                     networkCountryIso =
1351                             mTelephonyManager.getSimCountryIsoForPhone(mPhone.getPhoneId());
1352                 }
1353 
1354                 smsCategory =
1355                         SmsUsageMonitor.mergeShortCodeCategories(
1356                                 smsCategory,
1357                                 mSmsDispatchersController
1358                                         .getUsageMonitor()
1359                                         .checkDestination(
1360                                                 trackers[0].mDestAddress, networkCountryIso));
1361             }
1362 
1363             if (smsCategory == SmsManager.SMS_CATEGORY_NOT_SHORT_CODE
1364                     || smsCategory == SmsManager.SMS_CATEGORY_FREE_SHORT_CODE
1365                     || smsCategory == SmsManager.SMS_CATEGORY_STANDARD_SHORT_CODE) {
1366                 return true;    // not a premium short code
1367             }
1368 
1369             // Do not allow any premium sms during SuW
1370             if (Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
1371                 Rlog.e(TAG, "Can't send premium sms during Setup Wizard"
1372                         + " id: " + getMultiTrackermessageId(trackers));
1373                 return false;
1374             }
1375 
1376             // Wait for user confirmation unless the user has set permission to always allow/deny
1377             int premiumSmsPermission =
1378                     mSmsDispatchersController
1379                             .getUsageMonitor()
1380                             .getPremiumSmsPermission(trackers[0].getAppPackageName());
1381             if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
1382                 // First time trying to send to premium SMS.
1383                 premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
1384             }
1385 
1386             switch (premiumSmsPermission) {
1387                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
1388                     Rlog.d(TAG, "User approved this app to send to premium SMS"
1389                             + " id: " + getMultiTrackermessageId(trackers));
1390                     return true;
1391 
1392                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
1393                     Rlog.w(TAG, "User denied this app from sending to premium SMS"
1394                             + " id: " + getMultiTrackermessageId(trackers));
1395                     Message msg = obtainMessage(EVENT_SENDING_NOT_ALLOWED, trackers);
1396                     sendMessage(msg);
1397                     return false;   // reject this message
1398 
1399                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
1400                 default:
1401                     int event;
1402                     if (smsCategory == SmsManager.SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
1403                         event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
1404                     } else {
1405                         event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
1406                     }
1407                     sendMessage(obtainMessage(event, trackers));
1408                     return false;   // wait for user confirmation
1409             }
1410         }
1411     }
1412 
1413     /**
1414      * Deny sending a single or a multi-part SMS if the outgoing queue limit is reached. Used when
1415      * the message must be confirmed by the user due to excessive usage or potential premium SMS
1416      * detected.
1417      *
1418      * @param trackers the SmsTracker array for the message to send
1419      * @return true if the message was denied; false to continue with send confirmation
1420      */
denyIfQueueLimitReached(SmsTracker[] trackers)1421     private boolean denyIfQueueLimitReached(SmsTracker[] trackers) {
1422         // one SmsTracker array is treated as one message for checking queue limit.
1423         if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
1424             // Deny sending message when the queue limit is reached.
1425             Rlog.e(TAG, "Denied because queue limit reached"
1426                     + " id: " + getMultiTrackermessageId(trackers));
1427             handleSmsTrackersFailure(trackers, RESULT_ERROR_LIMIT_EXCEEDED, NO_ERROR_CODE);
1428             return true;
1429         }
1430         mPendingTrackerCount++;
1431         return false;
1432     }
1433 
1434     /**
1435      * Returns the label for the specified app package name.
1436      * @param appPackage the package name of the app requesting to send an SMS
1437      * @return the label for the specified app, or the package name if getApplicationInfo() fails
1438      */
getAppLabel(String appPackage, @UserIdInt int userId)1439     private CharSequence getAppLabel(String appPackage, @UserIdInt int userId) {
1440         PackageManager pm = mContext.getPackageManager();
1441         try {
1442             ApplicationInfo appInfo = pm.getApplicationInfoAsUser(appPackage, 0,
1443                 UserHandle.getUserHandleForUid(userId));
1444             return appInfo.loadSafeLabel(pm);
1445         } catch (PackageManager.NameNotFoundException e) {
1446             Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
1447             return appPackage;  // fall back to package name if we can't get app label
1448         }
1449     }
1450 
1451     /**
1452      * Post an alert when SMS needs confirmation due to excessive usage.
1453      *
1454      * @param trackers the SmsTracker array for the current message.
1455      */
handleReachSentLimit(SmsTracker[] trackers)1456     protected void handleReachSentLimit(SmsTracker[] trackers) {
1457         if (denyIfQueueLimitReached(trackers)) {
1458             return;     // queue limit reached; error was returned to caller
1459         }
1460 
1461         CharSequence appLabel = getAppLabel(trackers[0].getAppPackageName(), trackers[0].mUserId);
1462         Resources r = Resources.getSystem();
1463         Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
1464 
1465         // Construct ConfirmDialogListenter for Rate Limit handling
1466         ConfirmDialogListener listener =
1467                 new ConfirmDialogListener(trackers, null, ConfirmDialogListener.RATE_LIMIT);
1468 
1469         AlertDialog d = new AlertDialog.Builder(mContext)
1470                 .setTitle(R.string.sms_control_title)
1471                 .setIcon(R.drawable.stat_sys_warning)
1472                 .setMessage(messageText)
1473                 .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
1474                 .setNegativeButton(r.getString(R.string.sms_control_no), listener)
1475                 .setOnCancelListener(listener)
1476                 .create();
1477 
1478         d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1479         d.show();
1480     }
1481 
1482     /**
1483      * Post an alert for user confirmation when sending to a potential short code.
1484      *
1485      * @param isPremium true if the destination is known to be a premium short code
1486      * @param trackers the SmsTracker array for the current message.
1487      */
1488     @UnsupportedAppUsage
handleConfirmShortCode(boolean isPremium, SmsTracker[] trackers)1489     protected void handleConfirmShortCode(boolean isPremium, SmsTracker[] trackers) {
1490         if (denyIfQueueLimitReached(trackers)) {
1491             return;     // queue limit reached; error was returned to caller
1492         }
1493 
1494         int detailsId;
1495         if (isPremium) {
1496             detailsId = R.string.sms_premium_short_code_details;
1497         } else {
1498             detailsId = R.string.sms_short_code_details;
1499         }
1500 
1501         CharSequence appLabel = getAppLabel(trackers[0].getAppPackageName(), trackers[0].mUserId);
1502         Resources r = Resources.getSystem();
1503         Spanned messageText =
1504                 Html.fromHtml(
1505                         r.getString(
1506                                 R.string.sms_short_code_confirm_message,
1507                                 appLabel,
1508                                 trackers[0].mDestAddress));
1509 
1510         LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
1511                 Context.LAYOUT_INFLATER_SERVICE);
1512         View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
1513 
1514         // Construct ConfirmDialogListenter for short code message sending
1515         ConfirmDialogListener listener =
1516                 new ConfirmDialogListener(
1517                         trackers,
1518                         (TextView)
1519                                 layout.findViewById(R.id.sms_short_code_remember_undo_instruction),
1520                         ConfirmDialogListener.SHORT_CODE_MSG);
1521 
1522         TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
1523         messageView.setText(messageText);
1524 
1525         ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
1526                 R.id.sms_short_code_detail_layout);
1527         TextView detailsView = (TextView) detailsLayout.findViewById(
1528                 R.id.sms_short_code_detail_message);
1529         detailsView.setText(detailsId);
1530 
1531         CheckBox rememberChoice = (CheckBox) layout.findViewById(
1532                 R.id.sms_short_code_remember_choice_checkbox);
1533         rememberChoice.setOnCheckedChangeListener(listener);
1534 
1535         AlertDialog d = new AlertDialog.Builder(mContext)
1536                 .setView(layout)
1537                 .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
1538                 .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
1539                 .setOnCancelListener(listener)
1540                 .create();
1541 
1542         d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1543         d.show();
1544 
1545         listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
1546         listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
1547     }
1548 
1549     /**
1550      * Send the message along to the radio.
1551      *
1552      * @param tracker holds the SMS message to send
1553      */
1554     @UnsupportedAppUsage
sendSms(SmsTracker tracker)1555     protected abstract void sendSms(SmsTracker tracker);
1556 
1557     /**
1558      * Retry the message along to the radio.
1559      *
1560      * @param tracker holds the SMS message to send
1561      */
sendRetrySms(SmsTracker tracker)1562     public void sendRetrySms(SmsTracker tracker) {
1563         // re-routing to SmsDispatchersController
1564         if (mSmsDispatchersController != null) {
1565             mSmsDispatchersController.sendRetrySms(tracker);
1566         } else {
1567             Rlog.e(TAG, mSmsDispatchersController + " is null. Retry failed"
1568                     + " id: " + tracker.mMessageId);
1569         }
1570     }
1571 
handleSmsTrackersFailure(SmsTracker[] trackers, int error, int errorCode)1572     private void handleSmsTrackersFailure(SmsTracker[] trackers, int error, int errorCode) {
1573         for (SmsTracker tracker : trackers) {
1574             tracker.onFailed(mContext, error, errorCode);
1575         }
1576     }
1577 
1578     /**
1579      * Keeps track of an SMS that has been sent to the RIL, until it has
1580      * successfully been sent, or we're done trying.
1581      */
1582     public static class SmsTracker {
1583         // fields need to be public for derived SmsDispatchers
1584         @UnsupportedAppUsage
1585         private final HashMap<String, Object> mData;
1586         public int mRetryCount;
1587         // IMS retry counter. Nonzero indicates initial message was sent over IMS channel in RIL and
1588         // counts how many retries have been made on the IMS channel.
1589         // Used in older implementations where the message is sent over IMS using the RIL.
1590         public int mImsRetry;
1591         // Tag indicating that this SMS is being handled by the ImsSmsDispatcher. This tracker
1592         // should not try to use SMS over IMS over the RIL interface in this case when falling back.
1593         public boolean mUsesImsServiceForIms;
1594         @UnsupportedAppUsage
1595         public int mMessageRef;
1596         public boolean mExpectMore;
1597         public int mValidityPeriod;
1598         public int mPriority;
1599         String mFormat;
1600 
1601         @UnsupportedAppUsage
1602         public final PendingIntent mSentIntent;
1603         @UnsupportedAppUsage
1604         public final PendingIntent mDeliveryIntent;
1605 
1606         @UnsupportedAppUsage
1607         public final PackageInfo mAppInfo;
1608         @UnsupportedAppUsage
1609         public final String mDestAddress;
1610 
1611         public final SmsHeader mSmsHeader;
1612 
1613         @UnsupportedAppUsage
1614         private long mTimestamp = System.currentTimeMillis();
1615         @UnsupportedAppUsage
1616         public Uri mMessageUri; // Uri of persisted message if we wrote one
1617 
1618         // Reference to states of a multipart message that this part belongs to
1619         private AtomicInteger mUnsentPartCount;
1620         private AtomicBoolean mAnyPartFailed;
1621         // The full message content of a single part message
1622         // or a multipart message that this part belongs to
1623         private String mFullMessageText;
1624 
1625         private int mSubId;
1626 
1627         // If this is a text message (instead of data message)
1628         private boolean mIsText;
1629 
1630         @UnsupportedAppUsage
1631         private boolean mPersistMessage;
1632 
1633         // User who sends the SMS.
1634         private final @UserIdInt int mUserId;
1635 
1636         private final boolean mIsForVvm;
1637 
1638         public final long mMessageId;
1639 
SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader, boolean expectMore, String fullMessageText, int subId, boolean isText, boolean persistMessage, int userId, int priority, int validityPeriod, boolean isForVvm, long messageId)1640         private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1641                 PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format,
1642                 AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
1643                 SmsHeader smsHeader, boolean expectMore, String fullMessageText, int subId,
1644                 boolean isText, boolean persistMessage, int userId, int priority,
1645                 int validityPeriod, boolean isForVvm, long messageId) {
1646             mData = data;
1647             mSentIntent = sentIntent;
1648             mDeliveryIntent = deliveryIntent;
1649             mRetryCount = 0;
1650             mAppInfo = appInfo;
1651             mDestAddress = destAddr;
1652             mFormat = format;
1653             mExpectMore = expectMore;
1654             mImsRetry = 0;
1655             mUsesImsServiceForIms = false;
1656             mMessageRef = 0;
1657             mUnsentPartCount = unsentPartCount;
1658             mAnyPartFailed = anyPartFailed;
1659             mMessageUri = messageUri;
1660             mSmsHeader = smsHeader;
1661             mFullMessageText = fullMessageText;
1662             mSubId = subId;
1663             mIsText = isText;
1664             mPersistMessage = persistMessage;
1665             mUserId = userId;
1666             mPriority = priority;
1667             mValidityPeriod = validityPeriod;
1668             mIsForVvm = isForVvm;
1669             mMessageId = messageId;
1670         }
1671 
getData()1672         public HashMap<String, Object> getData() {
1673             return mData;
1674         }
1675 
1676         /**
1677          * Get the App package name
1678          * @return App package name info
1679          */
getAppPackageName()1680         public String getAppPackageName() {
1681             return mAppInfo != null ? mAppInfo.packageName : null;
1682         }
1683 
1684         /**
1685          * Update the status of this message if we persisted it
1686          */
1687         @UnsupportedAppUsage
updateSentMessageStatus(Context context, int status)1688         public void updateSentMessageStatus(Context context, int status) {
1689             if (mMessageUri != null) {
1690                 // If we wrote this message in writeSentMessage, update it now
1691                 ContentValues values = new ContentValues(1);
1692                 values.put(Sms.STATUS, status);
1693                 context.getContentResolver().update(mMessageUri, values, null, null);
1694             }
1695         }
1696 
1697         /**
1698          * Set the final state of a message: FAILED or SENT
1699          *
1700          * @param context The Context
1701          * @param messageType The final message type
1702          * @param errorCode The error code
1703          */
updateMessageState(Context context, int messageType, int errorCode)1704         private void updateMessageState(Context context, int messageType, int errorCode) {
1705             if (mMessageUri == null) {
1706                 return;
1707             }
1708             final ContentValues values = new ContentValues(2);
1709             values.put(Sms.TYPE, messageType);
1710             values.put(Sms.ERROR_CODE, errorCode);
1711             final long identity = Binder.clearCallingIdentity();
1712             try {
1713                 if (context.getContentResolver().update(mMessageUri, values,
1714                         null/*where*/, null/*selectionArgs*/) != 1) {
1715                     Rlog.e(TAG, "Failed to move message to " + messageType);
1716                 }
1717             } finally {
1718                 Binder.restoreCallingIdentity(identity);
1719             }
1720         }
1721 
1722         /**
1723          * Persist a sent SMS if required:
1724          * 1. It is a text message
1725          * 2. SmsApplication tells us to persist: sent from apps that are not default-SMS app or
1726          *    bluetooth
1727          *
1728          * @param context
1729          * @param messageType The folder to store (FAILED or SENT)
1730          * @param errorCode The current error code for this SMS or SMS part
1731          * @return The telephony provider URI if stored
1732          */
persistSentMessageIfRequired(Context context, int messageType, int errorCode)1733         private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) {
1734             if (!mIsText || !mPersistMessage ||
1735                     !SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) {
1736                 return null;
1737             }
1738             Rlog.d(TAG, "Persist SMS into "
1739                     + (messageType == Sms.MESSAGE_TYPE_FAILED ? "FAILED" : "SENT"));
1740             final ContentValues values = new ContentValues();
1741             values.put(Sms.SUBSCRIPTION_ID, mSubId);
1742             values.put(Sms.ADDRESS, mDestAddress);
1743             values.put(Sms.BODY, mFullMessageText);
1744             values.put(Sms.DATE, System.currentTimeMillis()); // milliseconds
1745             values.put(Sms.SEEN, 1);
1746             values.put(Sms.READ, 1);
1747             final String creator = mAppInfo != null ? mAppInfo.packageName : null;
1748             if (!TextUtils.isEmpty(creator)) {
1749                 values.put(Sms.CREATOR, creator);
1750             }
1751             if (mDeliveryIntent != null) {
1752                 values.put(Sms.STATUS, Telephony.Sms.STATUS_PENDING);
1753             }
1754             if (errorCode != NO_ERROR_CODE) {
1755                 values.put(Sms.ERROR_CODE, errorCode);
1756             }
1757             final long identity = Binder.clearCallingIdentity();
1758             final ContentResolver resolver = context.getContentResolver();
1759             try {
1760                 final Uri uri =  resolver.insert(Telephony.Sms.Sent.CONTENT_URI, values);
1761                 if (uri != null && messageType == Sms.MESSAGE_TYPE_FAILED) {
1762                     // Since we can't persist a message directly into FAILED box,
1763                     // we have to update the column after we persist it into SENT box.
1764                     // The gap between the state change is tiny so I would not expect
1765                     // it to cause any serious problem
1766                     // TODO: we should add a "failed" URI for this in SmsProvider?
1767                     final ContentValues updateValues = new ContentValues(1);
1768                     updateValues.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
1769                     resolver.update(uri, updateValues, null/*where*/, null/*selectionArgs*/);
1770                 }
1771                 return uri;
1772             } catch (Exception e) {
1773                 Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
1774                 return null;
1775             } finally {
1776                 Binder.restoreCallingIdentity(identity);
1777             }
1778         }
1779 
1780         /**
1781          * Persist or update an SMS depending on if we send a new message or a stored message
1782          *
1783          * @param context
1784          * @param messageType The message folder for this SMS, FAILED or SENT
1785          * @param errorCode The current error code for this SMS or SMS part
1786          */
persistOrUpdateMessage(Context context, int messageType, int errorCode)1787         private void persistOrUpdateMessage(Context context, int messageType, int errorCode) {
1788             if (mMessageUri != null) {
1789                 updateMessageState(context, messageType, errorCode);
1790             } else {
1791                 mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode);
1792             }
1793         }
1794 
1795         /**
1796          * Handle a failure of a single part message or a part of a multipart message
1797          *
1798          * @param context The Context
1799          * @param error The error to send back with
1800          * @param errorCode
1801          */
1802         @UnsupportedAppUsage
onFailed(Context context, int error, int errorCode)1803         public void onFailed(Context context, int error, int errorCode) {
1804             if (mAnyPartFailed != null) {
1805                 mAnyPartFailed.set(true);
1806             }
1807             // is single part or last part of multipart message
1808             boolean isSinglePartOrLastPart = true;
1809             if (mUnsentPartCount != null) {
1810                 isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1811             }
1812             if (isSinglePartOrLastPart) {
1813                 persistOrUpdateMessage(context, Sms.MESSAGE_TYPE_FAILED, errorCode);
1814             }
1815             if (mSentIntent != null) {
1816                 try {
1817                     // Extra information to send with the sent intent
1818                     Intent fillIn = new Intent();
1819                     if (mMessageUri != null) {
1820                         // Pass this to SMS apps so that they know where it is stored
1821                         fillIn.putExtra("uri", mMessageUri.toString());
1822                     }
1823                     if (errorCode != NO_ERROR_CODE) {
1824                         fillIn.putExtra("errorCode", errorCode);
1825                     }
1826                     if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1827                         // Is multipart and last part
1828                         fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1829                     }
1830                     if (mMessageId != 0L) {
1831                         // Send the id back to the caller so they can verify the message id
1832                         // with the one they passed to SmsManager.
1833                         fillIn.putExtra(MESSAGE_ID_EXTRA, mMessageId);
1834                     }
1835                     mSentIntent.send(context, error, fillIn);
1836                 } catch (CanceledException ex) {
1837                     Rlog.e(TAG, "Failed to send result"
1838                             + " id: " + mMessageId);
1839                 }
1840             }
1841         }
1842 
1843         /**
1844          * Handle the sent of a single part message or a part of a multipart message
1845          *
1846          * @param context The Context
1847          */
1848         @UnsupportedAppUsage
onSent(Context context)1849         public void onSent(Context context) {
1850             // is single part or last part of multipart message
1851             boolean isSinglePartOrLastPart = true;
1852             if (mUnsentPartCount != null) {
1853                 isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1854             }
1855             if (isSinglePartOrLastPart) {
1856                 int messageType = Sms.MESSAGE_TYPE_SENT;
1857                 if (mAnyPartFailed != null && mAnyPartFailed.get()) {
1858                     messageType = Sms.MESSAGE_TYPE_FAILED;
1859                 }
1860                 persistOrUpdateMessage(context, messageType, NO_ERROR_CODE);
1861             }
1862             if (mSentIntent != null) {
1863                 try {
1864                     // Extra information to send with the sent intent
1865                     Intent fillIn = new Intent();
1866                     if (mMessageUri != null) {
1867                         // Pass this to SMS apps so that they know where it is stored
1868                         fillIn.putExtra("uri", mMessageUri.toString());
1869                     }
1870                     if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1871                         // Is multipart and last part
1872                         fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1873                     }
1874                     mSentIntent.send(context, Activity.RESULT_OK, fillIn);
1875                 } catch (CanceledException ex) {
1876                     Rlog.e(TAG, "Failed to send result");
1877                 }
1878             }
1879         }
1880     }
1881 
getSmsTracker(String callingPackage, HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader, boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, int priority, int validityPeriod, boolean isForVvm, long messageId)1882     protected SmsTracker getSmsTracker(String callingPackage, HashMap<String, Object> data,
1883             PendingIntent sentIntent, PendingIntent deliveryIntent, String format,
1884             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
1885             SmsHeader smsHeader, boolean expectMore, String fullMessageText, boolean isText,
1886             boolean persistMessage, int priority, int validityPeriod, boolean isForVvm,
1887             long messageId) {
1888         // Get package info via packagemanager
1889         UserHandle callingUser = UserHandle.getUserHandleForUid(Binder.getCallingUid());
1890         final int userId = callingUser.getIdentifier();
1891         PackageManager pm = mContext.createContextAsUser(callingUser, 0).getPackageManager();
1892         PackageInfo appInfo = null;
1893         try {
1894             appInfo = pm.getPackageInfo(callingPackage, PackageManager.GET_SIGNATURES);
1895         } catch (PackageManager.NameNotFoundException e) {
1896             // error will be logged in sendRawPdu
1897         }
1898         // Strip non-digits from destination phone number before checking for short codes
1899         // and before displaying the number to the user if confirmation is required.
1900         String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
1901         return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format,
1902                 unsentPartCount, anyPartFailed, messageUri, smsHeader, expectMore,
1903                 fullMessageText, getSubId(), isText, persistMessage, userId, priority,
1904                 validityPeriod, isForVvm, messageId);
1905     }
1906 
getSmsTracker(String callingPackage, HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, boolean isForVvm, long messageId)1907     protected SmsTracker getSmsTracker(String callingPackage, HashMap<String, Object> data,
1908             PendingIntent sentIntent, PendingIntent deliveryIntent, String format, Uri messageUri,
1909             boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage,
1910             boolean isForVvm, long messageId) {
1911         return getSmsTracker(callingPackage, data, sentIntent, deliveryIntent, format,
1912                 null/*unsentPartCount*/, null/*anyPartFailed*/, messageUri, null/*smsHeader*/,
1913                 expectMore, fullMessageText, isText, persistMessage,
1914                 SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, isForVvm,
1915                 messageId);
1916     }
1917 
getSmsTracker(String callingPackage, HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, int priority, int validityPeriod, boolean isForVvm, long messageId)1918     protected SmsTracker getSmsTracker(String callingPackage, HashMap<String, Object> data,
1919             PendingIntent sentIntent, PendingIntent deliveryIntent, String format, Uri messageUri,
1920             boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage,
1921             int priority, int validityPeriod, boolean isForVvm, long messageId) {
1922         return getSmsTracker(callingPackage, data, sentIntent, deliveryIntent, format,
1923                 null/*unsentPartCount*/, null/*anyPartFailed*/, messageUri, null/*smsHeader*/,
1924                 expectMore, fullMessageText, isText, persistMessage, priority, validityPeriod,
1925                 isForVvm, messageId);
1926     }
1927 
getSmsTrackerMap(String destAddr, String scAddr, String text, SmsMessageBase.SubmitPduBase pdu)1928     protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
1929             String text, SmsMessageBase.SubmitPduBase pdu) {
1930         HashMap<String, Object> map = new HashMap<String, Object>();
1931         map.put(MAP_KEY_DEST_ADDR, destAddr);
1932         map.put(MAP_KEY_SC_ADDR, scAddr);
1933         map.put(MAP_KEY_TEXT, text);
1934         map.put(MAP_KEY_SMSC, pdu.encodedScAddress);
1935         map.put(MAP_KEY_PDU, pdu.encodedMessage);
1936         return map;
1937     }
1938 
getSmsTrackerMap(String destAddr, String scAddr, int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu)1939     protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
1940             int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
1941         HashMap<String, Object> map = new HashMap<String, Object>();
1942         map.put(MAP_KEY_DEST_ADDR, destAddr);
1943         map.put(MAP_KEY_SC_ADDR, scAddr);
1944         map.put(MAP_KEY_DEST_PORT, destPort);
1945         map.put(MAP_KEY_DATA, data);
1946         map.put(MAP_KEY_SMSC, pdu.encodedScAddress);
1947         map.put(MAP_KEY_PDU, pdu.encodedMessage);
1948         return map;
1949     }
1950 
1951     /**
1952      * Dialog listener for SMS confirmation dialog.
1953      */
1954     private final class ConfirmDialogListener
1955             implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
1956             CompoundButton.OnCheckedChangeListener {
1957 
1958         private final SmsTracker[] mTrackers;
1959         @UnsupportedAppUsage
1960         private Button mPositiveButton;
1961         @UnsupportedAppUsage
1962         private Button mNegativeButton;
1963         private boolean mRememberChoice;    // default is unchecked
1964         @UnsupportedAppUsage
1965         private final TextView mRememberUndoInstruction;
1966         private int mConfirmationType;  // 0 - Short Code Msg Sending; 1 - Rate Limit Exceeded
1967         private static final int SHORT_CODE_MSG = 0; // Short Code Msg
1968         private static final int RATE_LIMIT = 1; // Rate Limit Exceeded
1969         private static final int NEVER_ALLOW = 1; // Never Allow
1970 
ConfirmDialogListener(SmsTracker[] trackers, TextView textView, int confirmationType)1971         ConfirmDialogListener(SmsTracker[] trackers, TextView textView, int confirmationType) {
1972             mTrackers = trackers;
1973             mRememberUndoInstruction = textView;
1974             mConfirmationType = confirmationType;
1975         }
1976 
setPositiveButton(Button button)1977         void setPositiveButton(Button button) {
1978             mPositiveButton = button;
1979         }
1980 
setNegativeButton(Button button)1981         void setNegativeButton(Button button) {
1982             mNegativeButton = button;
1983         }
1984 
1985         @Override
onClick(DialogInterface dialog, int which)1986         public void onClick(DialogInterface dialog, int which) {
1987             // Always set the SMS permission so that Settings will show a permission setting
1988             // for the app (it won't be shown until after the app tries to send to a short code).
1989             int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
1990 
1991             if (which == DialogInterface.BUTTON_POSITIVE) {
1992                 Rlog.d(TAG, "CONFIRM sending SMS");
1993                 // XXX this is lossy- apps can have more than one signature
1994                 EventLog.writeEvent(
1995                         EventLogTags.EXP_DET_SMS_SENT_BY_USER,
1996                         mTrackers[0].mAppInfo.applicationInfo == null
1997                                 ? -1
1998                                 : mTrackers[0].mAppInfo.applicationInfo.uid);
1999                 sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTrackers));
2000                 if (mRememberChoice) {
2001                     newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
2002                 }
2003             } else if (which == DialogInterface.BUTTON_NEGATIVE) {
2004                 Rlog.d(TAG, "DENY sending SMS");
2005                 // XXX this is lossy- apps can have more than one signature
2006                 EventLog.writeEvent(
2007                         EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
2008                         mTrackers[0].mAppInfo.applicationInfo == null
2009                                 ? -1
2010                                 : mTrackers[0].mAppInfo.applicationInfo.uid);
2011                 Message msg = obtainMessage(EVENT_STOP_SENDING, mTrackers);
2012                 msg.arg1 = mConfirmationType;
2013                 if (mRememberChoice) {
2014                     newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
2015                     msg.arg2 = ConfirmDialogListener.NEVER_ALLOW;
2016                 }
2017                 sendMessage(msg);
2018             }
2019             mSmsDispatchersController.setPremiumSmsPermission(
2020                     mTrackers[0].getAppPackageName(), newSmsPermission);
2021         }
2022 
2023         @Override
onCancel(DialogInterface dialog)2024         public void onCancel(DialogInterface dialog) {
2025             Rlog.d(TAG, "dialog dismissed: don't send SMS");
2026             Message msg = obtainMessage(EVENT_STOP_SENDING, mTrackers);
2027             msg.arg1 = mConfirmationType;
2028             sendMessage(msg);
2029         }
2030 
2031         @Override
onCheckedChanged(CompoundButton buttonView, boolean isChecked)2032         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
2033             Rlog.d(TAG, "remember this choice: " + isChecked);
2034             mRememberChoice = isChecked;
2035             if (isChecked) {
2036                 mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
2037                 mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
2038                 if (mRememberUndoInstruction != null) {
2039                     mRememberUndoInstruction
2040                             .setText(R.string.sms_short_code_remember_undo_instruction);
2041                     mRememberUndoInstruction.setPadding(0,0,0,32);
2042                 }
2043             } else {
2044                 mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
2045                 mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
2046                 if (mRememberUndoInstruction != null) {
2047                     mRememberUndoInstruction.setText("");
2048                     mRememberUndoInstruction.setPadding(0,0,0,0);
2049                 }
2050             }
2051         }
2052     }
2053 
isIms()2054     public boolean isIms() {
2055         if (mSmsDispatchersController != null) {
2056             return mSmsDispatchersController.isIms();
2057         } else {
2058             Rlog.e(TAG, "mSmsDispatchersController  is null");
2059             return false;
2060         }
2061     }
2062 
2063     @UnsupportedAppUsage
getMultipartMessageText(ArrayList<String> parts)2064     private String getMultipartMessageText(ArrayList<String> parts) {
2065         final StringBuilder sb = new StringBuilder();
2066         for (String part : parts) {
2067             if (part != null) {
2068                 sb.append(part);
2069             }
2070         }
2071         return sb.toString();
2072     }
2073 
2074     @UnsupportedAppUsage
getCarrierAppPackageName()2075     protected String getCarrierAppPackageName() {
2076         UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
2077         if (card == null) {
2078             return null;
2079         }
2080 
2081         List<String> carrierPackages = card.getCarrierPackageNamesForIntent(
2082             mContext.getPackageManager(), new Intent(CarrierMessagingService.SERVICE_INTERFACE));
2083         if (carrierPackages != null && carrierPackages.size() == 1) {
2084             return carrierPackages.get(0);
2085         }
2086         // If there is no carrier package which implements CarrierMessagingService, then lookup if
2087         // for a carrierImsPackage that implements CarrierMessagingService.
2088         return CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
2089                 new Intent(CarrierMessagingService.SERVICE_INTERFACE));
2090     }
2091 
2092     @UnsupportedAppUsage
getSubId()2093     protected int getSubId() {
2094         return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.getPhoneId());
2095     }
2096 
2097     @UnsupportedAppUsage
checkCallerIsPhoneOrCarrierApp()2098     private void checkCallerIsPhoneOrCarrierApp() {
2099         int uid = Binder.getCallingUid();
2100         int appId = UserHandle.getAppId(uid);
2101         if (appId == Process.PHONE_UID || uid == 0) {
2102             return;
2103         }
2104         try {
2105             PackageManager pm = mContext.getPackageManager();
2106             ApplicationInfo ai = pm.getApplicationInfo(getCarrierAppPackageName(), 0);
2107             if (UserHandle.getAppId(ai.uid) != UserHandle.getAppId(Binder.getCallingUid())) {
2108                 throw new SecurityException("Caller is not phone or carrier app!");
2109             }
2110         } catch (PackageManager.NameNotFoundException re) {
2111             throw new SecurityException("Caller is not phone or carrier app!");
2112         }
2113     }
2114 
isCdmaMo()2115     protected boolean isCdmaMo() {
2116         return mSmsDispatchersController.isCdmaMo();
2117     }
2118 
isAscii7bitSupportedForLongMessage()2119     private boolean isAscii7bitSupportedForLongMessage() {
2120         //TODO: Do not rely on calling identity here, we should store UID & clear identity earlier.
2121         long token = Binder.clearCallingIdentity();
2122         try {
2123             CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
2124                     Context.CARRIER_CONFIG_SERVICE);
2125             PersistableBundle pb = null;
2126             pb = configManager.getConfigForSubId(mPhone.getSubId());
2127             if (pb != null) {
2128                 return pb.getBoolean(CarrierConfigManager
2129                         .KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL);
2130             }
2131             return false;
2132         } finally {
2133             Binder.restoreCallingIdentity(token);
2134         }
2135     }
2136 }
2137