• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony;
18 import android.annotation.Nullable;
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.PendingIntent;
22 import android.app.PendingIntent.CanceledException;
23 import android.content.ContentResolver;
24 import android.content.ContentValues;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.pm.ApplicationInfo;
29 import android.content.pm.PackageInfo;
30 import android.content.pm.PackageManager;
31 import android.content.res.Resources;
32 import android.database.ContentObserver;
33 import android.database.sqlite.SqliteWrapper;
34 import android.net.Uri;
35 import android.os.AsyncResult;
36 import android.os.Binder;
37 import android.os.Handler;
38 import android.os.Message;
39 import android.os.Process;
40 import android.os.RemoteException;
41 import android.os.UserHandle;
42 import android.provider.Settings;
43 import android.provider.Telephony;
44 import android.provider.Telephony.Sms;
45 import android.service.carrier.CarrierMessagingService;
46 import android.service.carrier.ICarrierMessagingCallback;
47 import android.service.carrier.ICarrierMessagingService;
48 import android.telephony.CarrierMessagingServiceManager;
49 import android.telephony.PhoneNumberUtils;
50 import android.telephony.Rlog;
51 import android.telephony.ServiceState;
52 import android.telephony.TelephonyManager;
53 import android.text.Html;
54 import android.text.Spanned;
55 import android.text.TextUtils;
56 import android.util.EventLog;
57 import android.view.LayoutInflater;
58 import android.view.View;
59 import android.view.ViewGroup;
60 import android.view.WindowManager;
61 import android.widget.Button;
62 import android.widget.CheckBox;
63 import android.widget.CompoundButton;
64 import android.widget.TextView;
65 
66 import com.android.internal.R;
67 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
68 import com.android.internal.telephony.uicc.UiccCard;
69 import com.android.internal.telephony.uicc.UiccController;
70 
71 import java.util.ArrayList;
72 import java.util.HashMap;
73 import java.util.List;
74 import java.util.Random;
75 import java.util.concurrent.atomic.AtomicBoolean;
76 import java.util.concurrent.atomic.AtomicInteger;
77 
78 import static android.Manifest.permission.SEND_SMS_NO_CONFIRMATION;
79 import static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
80 import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
81 import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
82 import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
83 import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
84 import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
85 
86 public abstract class SMSDispatcher extends Handler {
87     static final String TAG = "SMSDispatcher";    // accessed from inner class
88     static final boolean DBG = false;
89     private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
90 
91     private static final int PREMIUM_RULE_USE_SIM = 1;
92     private static final int PREMIUM_RULE_USE_NETWORK = 2;
93     private static final int PREMIUM_RULE_USE_BOTH = 3;
94     private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
95     private final SettingsObserver mSettingsObserver;
96 
97     /** SMS send complete. */
98     protected static final int EVENT_SEND_SMS_COMPLETE = 2;
99 
100     /** Retry sending a previously failed SMS message */
101     private static final int EVENT_SEND_RETRY = 3;
102 
103     /** Confirmation required for sending a large number of messages. */
104     private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
105 
106     /** Send the user confirmed SMS */
107     static final int EVENT_SEND_CONFIRMED_SMS = 5;  // accessed from inner class
108 
109     /** Don't send SMS (user did not confirm). */
110     static final int EVENT_STOP_SENDING = 7;        // accessed from inner class
111 
112     /** Confirmation required for third-party apps sending to an SMS short code. */
113     private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
114 
115     /** Confirmation required for third-party apps sending to an SMS short code. */
116     private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
117 
118     /** Handle status report from {@code CdmaInboundSmsHandler}. */
119     protected static final int EVENT_HANDLE_STATUS_REPORT = 10;
120 
121     /** Radio is ON */
122     protected static final int EVENT_RADIO_ON = 11;
123 
124     /** IMS registration/SMS format changed */
125     protected static final int EVENT_IMS_STATE_CHANGED = 12;
126 
127     /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */
128     protected static final int EVENT_IMS_STATE_DONE = 13;
129 
130     // other
131     protected static final int EVENT_NEW_ICC_SMS = 14;
132     protected static final int EVENT_ICC_CHANGED = 15;
133 
134     protected Phone mPhone;
135     protected final Context mContext;
136     protected final ContentResolver mResolver;
137     protected final CommandsInterface mCi;
138     protected final TelephonyManager mTelephonyManager;
139 
140     /** Maximum number of times to retry sending a failed SMS. */
141     private static final int MAX_SEND_RETRIES = 3;
142     /** Delay before next send attempt on a failed SMS, in milliseconds. */
143     private static final int SEND_RETRY_DELAY = 2000;
144     /** single part SMS */
145     private static final int SINGLE_PART_SMS = 1;
146     /** Message sending queue limit */
147     private static final int MO_MSG_QUEUE_LIMIT = 5;
148 
149     /**
150      * Message reference for a CONCATENATED_8_BIT_REFERENCE or
151      * CONCATENATED_16_BIT_REFERENCE message set.  Should be
152      * incremented for each set of concatenated messages.
153      * Static field shared by all dispatcher objects.
154      */
155     private static int sConcatenatedRef = new Random().nextInt(256);
156 
157     /** Outgoing message counter. Shared by all dispatchers. */
158     private SmsUsageMonitor mUsageMonitor;
159 
160     private ImsSMSDispatcher mImsSMSDispatcher;
161 
162     /** Number of outgoing SmsTrackers waiting for user confirmation. */
163     private int mPendingTrackerCount;
164 
165     /* Flags indicating whether the current device allows sms service */
166     protected boolean mSmsCapable = true;
167     protected boolean mSmsSendDisabled;
168 
getNextConcatenatedRef()169     protected static int getNextConcatenatedRef() {
170         sConcatenatedRef += 1;
171         return sConcatenatedRef;
172     }
173 
174     /**
175      * Create a new SMS dispatcher.
176      * @param phone the Phone to use
177      * @param usageMonitor the SmsUsageMonitor to use
178      */
SMSDispatcher(Phone phone, SmsUsageMonitor usageMonitor, ImsSMSDispatcher imsSMSDispatcher)179     protected SMSDispatcher(Phone phone, SmsUsageMonitor usageMonitor,
180             ImsSMSDispatcher imsSMSDispatcher) {
181         mPhone = phone;
182         mImsSMSDispatcher = imsSMSDispatcher;
183         mContext = phone.getContext();
184         mResolver = mContext.getContentResolver();
185         mCi = phone.mCi;
186         mUsageMonitor = usageMonitor;
187         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
188         mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
189         mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
190                 Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
191 
192         mSmsCapable = mContext.getResources().getBoolean(
193                 com.android.internal.R.bool.config_sms_capable);
194         mSmsSendDisabled = !mTelephonyManager.getSmsSendCapableForPhone(
195                 mPhone.getPhoneId(), mSmsCapable);
196         Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
197                 + " mSmsSendDisabled=" + mSmsSendDisabled);
198     }
199 
200     /**
201      * Observe the secure setting for updated premium sms determination rules
202      */
203     private static class SettingsObserver extends ContentObserver {
204         private final AtomicInteger mPremiumSmsRule;
205         private final Context mContext;
SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context)206         SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
207             super(handler);
208             mPremiumSmsRule = premiumSmsRule;
209             mContext = context;
210             onChange(false); // load initial value;
211         }
212 
213         @Override
onChange(boolean selfChange)214         public void onChange(boolean selfChange) {
215             mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
216                     Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
217         }
218     }
219 
updatePhoneObject(Phone phone)220     protected void updatePhoneObject(Phone phone) {
221         mPhone = phone;
222         mUsageMonitor = phone.mSmsUsageMonitor;
223         Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() );
224     }
225 
226     /** Unregister for incoming SMS events. */
dispose()227     public void dispose() {
228         mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
229     }
230 
231     /**
232      * The format of the message PDU in the associated broadcast intent.
233      * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
234      * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
235      *
236      * Note: All applications which handle incoming SMS messages by processing the
237      * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
238      * into the new methods in {@link android.telephony.SmsMessage} which take an
239      * extra format parameter. This is required in order to correctly decode the PDU on
240      * devices which require support for both 3GPP and 3GPP2 formats at the same time,
241      * such as CDMA/LTE devices and GSM/CDMA world phones.
242      *
243      * @return the format of the message PDU
244      */
getFormat()245     protected abstract String getFormat();
246 
247     /**
248      * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports
249      * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}.
250      * @param o the SmsMessage containing the status report
251      */
handleStatusReport(Object o)252     protected void handleStatusReport(Object o) {
253         Rlog.d(TAG, "handleStatusReport() called with no subclass.");
254     }
255 
256     /* TODO: Need to figure out how to keep track of status report routing in a
257      *       persistent manner. If the phone process restarts (reboot or crash),
258      *       we will lose this list and any status reports that come in after
259      *       will be dropped.
260      */
261     /** Sent messages awaiting a delivery status report. */
262     protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
263 
264     /**
265      * Handles events coming from the phone stack. Overridden from handler.
266      *
267      * @param msg the message to handle
268      */
269     @Override
handleMessage(Message msg)270     public void handleMessage(Message msg) {
271         switch (msg.what) {
272         case EVENT_SEND_SMS_COMPLETE:
273             // An outbound SMS has been successfully transferred, or failed.
274             handleSendComplete((AsyncResult) msg.obj);
275             break;
276 
277         case EVENT_SEND_RETRY:
278             Rlog.d(TAG, "SMS retry..");
279             sendRetrySms((SmsTracker) msg.obj);
280             break;
281 
282         case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
283             handleReachSentLimit((SmsTracker)(msg.obj));
284             break;
285 
286         case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
287             handleConfirmShortCode(false, (SmsTracker)(msg.obj));
288             break;
289 
290         case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
291             handleConfirmShortCode(true, (SmsTracker)(msg.obj));
292             break;
293 
294         case EVENT_SEND_CONFIRMED_SMS:
295         {
296             SmsTracker tracker = (SmsTracker) msg.obj;
297             if (tracker.isMultipart()) {
298                 sendMultipartSms(tracker);
299             } else {
300                 if (mPendingTrackerCount > 1) {
301                     tracker.mExpectMore = true;
302                 } else {
303                     tracker.mExpectMore = false;
304                 }
305                 sendSms(tracker);
306             }
307             mPendingTrackerCount--;
308             break;
309         }
310 
311         case EVENT_STOP_SENDING:
312         {
313             SmsTracker tracker = (SmsTracker) msg.obj;
314             tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
315             mPendingTrackerCount--;
316             break;
317         }
318 
319         case EVENT_HANDLE_STATUS_REPORT:
320             handleStatusReport(msg.obj);
321             break;
322 
323         default:
324             Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
325         }
326     }
327 
328     /**
329      * Use the carrier messaging service to send a data or text SMS.
330      */
331     protected abstract class SmsSender extends CarrierMessagingServiceManager {
332         protected final SmsTracker mTracker;
333         // Initialized in sendSmsByCarrierApp
334         protected volatile SmsSenderCallback mSenderCallback;
335 
SmsSender(SmsTracker tracker)336         protected SmsSender(SmsTracker tracker) {
337             mTracker = tracker;
338         }
339 
sendSmsByCarrierApp(String carrierPackageName, SmsSenderCallback senderCallback)340         public void sendSmsByCarrierApp(String carrierPackageName,
341                                         SmsSenderCallback senderCallback) {
342             mSenderCallback = senderCallback;
343             if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
344                 Rlog.e(TAG, "bindService() for carrier messaging service failed");
345                 mSenderCallback.onSendSmsComplete(
346                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
347                         0 /* messageRef */);
348             } else {
349                 Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
350             }
351         }
352     }
353 
getSendSmsFlag(@ullable PendingIntent deliveryIntent)354     private static int getSendSmsFlag(@Nullable PendingIntent deliveryIntent) {
355         if (deliveryIntent == null) {
356             return 0;
357         }
358         return CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS;
359     }
360 
361     /**
362      * Use the carrier messaging service to send a text SMS.
363      */
364     protected final class TextSmsSender extends SmsSender {
TextSmsSender(SmsTracker tracker)365         public TextSmsSender(SmsTracker tracker) {
366             super(tracker);
367         }
368 
369         @Override
onServiceReady(ICarrierMessagingService carrierMessagingService)370         protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
371             HashMap<String, Object> map = mTracker.getData();
372             String text = (String) map.get("text");
373 
374             if (text != null) {
375                 try {
376                     carrierMessagingService.sendTextSms(text, getSubId(),
377                             mTracker.mDestAddress, getSendSmsFlag(mTracker.mDeliveryIntent),
378                             mSenderCallback);
379                 } catch (RemoteException e) {
380                     Rlog.e(TAG, "Exception sending the SMS: " + e);
381                     mSenderCallback.onSendSmsComplete(
382                             CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
383                             0 /* messageRef */);
384                 }
385             } else {
386                 mSenderCallback.onSendSmsComplete(
387                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
388                         0 /* messageRef */);
389             }
390         }
391     }
392 
393     /**
394      * Use the carrier messaging service to send a data SMS.
395      */
396     protected final class DataSmsSender extends SmsSender {
DataSmsSender(SmsTracker tracker)397         public DataSmsSender(SmsTracker tracker) {
398             super(tracker);
399         }
400 
401         @Override
onServiceReady(ICarrierMessagingService carrierMessagingService)402         protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
403             HashMap<String, Object> map = mTracker.getData();
404             byte[] data = (byte[]) map.get("data");
405             int destPort = (int) map.get("destPort");
406 
407             if (data != null) {
408                 try {
409                     carrierMessagingService.sendDataSms(data, getSubId(),
410                             mTracker.mDestAddress, destPort,
411                             getSendSmsFlag(mTracker.mDeliveryIntent), mSenderCallback);
412                 } catch (RemoteException e) {
413                     Rlog.e(TAG, "Exception sending the SMS: " + e);
414                     mSenderCallback.onSendSmsComplete(
415                             CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
416                             0 /* messageRef */);
417                 }
418             } else {
419                 mSenderCallback.onSendSmsComplete(
420                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
421                         0 /* messageRef */);
422             }
423         }
424     }
425 
426     /**
427      * Callback for TextSmsSender and DataSmsSender from the carrier messaging service.
428      * Once the result is ready, the carrier messaging service connection is disposed.
429      */
430     protected final class SmsSenderCallback extends ICarrierMessagingCallback.Stub {
431         private final SmsSender mSmsSender;
432 
SmsSenderCallback(SmsSender smsSender)433         public SmsSenderCallback(SmsSender smsSender) {
434             mSmsSender = smsSender;
435         }
436 
437         /**
438          * This method should be called only once.
439          */
440         @Override
onSendSmsComplete(int result, int messageRef)441         public void onSendSmsComplete(int result, int messageRef) {
442             checkCallerIsPhoneOrCarrierApp();
443             final long identity = Binder.clearCallingIdentity();
444             try {
445                 mSmsSender.disposeConnection(mContext);
446                 processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
447             } finally {
448                 Binder.restoreCallingIdentity(identity);
449             }
450         }
451 
452         @Override
onSendMultipartSmsComplete(int result, int[] messageRefs)453         public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
454             Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result);
455         }
456 
457         @Override
onFilterComplete(int result)458         public void onFilterComplete(int result) {
459             Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
460         }
461 
462         @Override
onSendMmsComplete(int result, byte[] sendConfPdu)463         public void onSendMmsComplete(int result, byte[] sendConfPdu) {
464             Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
465         }
466 
467         @Override
onDownloadMmsComplete(int result)468         public void onDownloadMmsComplete(int result) {
469             Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
470         }
471     }
472 
processSendSmsResponse(SmsTracker tracker, int result, int messageRef)473     private void processSendSmsResponse(SmsTracker tracker, int result, int messageRef) {
474         if (tracker == null) {
475             Rlog.e(TAG, "processSendSmsResponse: null tracker");
476             return;
477         }
478 
479         SmsResponse smsResponse = new SmsResponse(
480                 messageRef, null /* ackPdu */, -1 /* unknown error code */);
481 
482         switch (result) {
483         case CarrierMessagingService.SEND_STATUS_OK:
484             Rlog.d(TAG, "Sending SMS by IP succeeded.");
485             sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
486                                       new AsyncResult(tracker,
487                                                       smsResponse,
488                                                       null /* exception*/ )));
489             break;
490         case CarrierMessagingService.SEND_STATUS_ERROR:
491             Rlog.d(TAG, "Sending SMS by IP failed.");
492             sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
493                     new AsyncResult(tracker, smsResponse,
494                             new CommandException(CommandException.Error.GENERIC_FAILURE))));
495             break;
496         case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
497             Rlog.d(TAG, "Sending SMS by IP failed. Retry on carrier network.");
498             sendSubmitPdu(tracker);
499             break;
500         default:
501             Rlog.d(TAG, "Unknown result " + result + " Retry on carrier network.");
502             sendSubmitPdu(tracker);
503         }
504     }
505 
506     /**
507      * Use the carrier messaging service to send a multipart text SMS.
508      */
509     private final class MultipartSmsSender extends CarrierMessagingServiceManager {
510         private final List<String> mParts;
511         public final SmsTracker[] mTrackers;
512         // Initialized in sendSmsByCarrierApp
513         private volatile MultipartSmsSenderCallback mSenderCallback;
514 
MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers)515         MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) {
516             mParts = parts;
517             mTrackers = trackers;
518         }
519 
sendSmsByCarrierApp(String carrierPackageName, MultipartSmsSenderCallback senderCallback)520         void sendSmsByCarrierApp(String carrierPackageName,
521                                  MultipartSmsSenderCallback senderCallback) {
522             mSenderCallback = senderCallback;
523             if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
524                 Rlog.e(TAG, "bindService() for carrier messaging service failed");
525                 mSenderCallback.onSendMultipartSmsComplete(
526                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
527                         null /* smsResponse */);
528             } else {
529                 Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
530             }
531         }
532 
533         @Override
onServiceReady(ICarrierMessagingService carrierMessagingService)534         protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
535             try {
536                 carrierMessagingService.sendMultipartTextSms(
537                         mParts, getSubId(), mTrackers[0].mDestAddress,
538                         getSendSmsFlag(mTrackers[0].mDeliveryIntent), mSenderCallback);
539             } catch (RemoteException e) {
540                 Rlog.e(TAG, "Exception sending the SMS: " + e);
541                 mSenderCallback.onSendMultipartSmsComplete(
542                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
543                         null /* smsResponse */);
544             }
545         }
546     }
547 
548     /**
549      * Callback for MultipartSmsSender from the carrier messaging service.
550      * Once the result is ready, the carrier messaging service connection is disposed.
551      */
552     private final class MultipartSmsSenderCallback extends ICarrierMessagingCallback.Stub {
553         private final MultipartSmsSender mSmsSender;
554 
MultipartSmsSenderCallback(MultipartSmsSender smsSender)555         MultipartSmsSenderCallback(MultipartSmsSender smsSender) {
556             mSmsSender = smsSender;
557         }
558 
559         @Override
onSendSmsComplete(int result, int messageRef)560         public void onSendSmsComplete(int result, int messageRef) {
561             Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result);
562         }
563 
564         /**
565          * This method should be called only once.
566          */
567         @Override
onSendMultipartSmsComplete(int result, int[] messageRefs)568         public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
569             mSmsSender.disposeConnection(mContext);
570 
571             if (mSmsSender.mTrackers == null) {
572                 Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers.");
573                 return;
574             }
575 
576             checkCallerIsPhoneOrCarrierApp();
577             final long identity = Binder.clearCallingIdentity();
578             try {
579                 for (int i = 0; i < mSmsSender.mTrackers.length; i++) {
580                     int messageRef = 0;
581                     if (messageRefs != null && messageRefs.length > i) {
582                         messageRef = messageRefs[i];
583                     }
584                     processSendSmsResponse(mSmsSender.mTrackers[i], result, messageRef);
585                 }
586             } finally {
587                 Binder.restoreCallingIdentity(identity);
588             }
589         }
590 
591         @Override
onFilterComplete(int result)592         public void onFilterComplete(int result) {
593             Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
594         }
595 
596         @Override
onSendMmsComplete(int result, byte[] sendConfPdu)597         public void onSendMmsComplete(int result, byte[] sendConfPdu) {
598             Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
599         }
600 
601         @Override
onDownloadMmsComplete(int result)602         public void onDownloadMmsComplete(int result) {
603             Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
604         }
605     }
606 
607     /**
608      * Send an SMS PDU. Usually just calls {@link sendRawPdu}.
609      */
sendSubmitPdu(SmsTracker tracker)610     protected abstract void sendSubmitPdu(SmsTracker tracker);
611 
612     /**
613      * Called when SMS send completes. Broadcasts a sentIntent on success.
614      * On failure, either sets up retries or broadcasts a sentIntent with
615      * the failure in the result code.
616      *
617      * @param ar AsyncResult passed into the message handler.  ar.result should
618      *           an SmsResponse instance if send was successful.  ar.userObj
619      *           should be an SmsTracker instance.
620      */
handleSendComplete(AsyncResult ar)621     protected void handleSendComplete(AsyncResult ar) {
622         SmsTracker tracker = (SmsTracker) ar.userObj;
623         PendingIntent sentIntent = tracker.mSentIntent;
624 
625         if (ar.result != null) {
626             tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
627         } else {
628             Rlog.d(TAG, "SmsResponse was null");
629         }
630 
631         if (ar.exception == null) {
632             if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
633 
634             if (tracker.mDeliveryIntent != null) {
635                 // Expecting a status report.  Add it to the list.
636                 deliveryPendingList.add(tracker);
637             }
638             tracker.onSent(mContext);
639         } else {
640             if (DBG) Rlog.d(TAG, "SMS send failed");
641 
642             int ss = mPhone.getServiceState().getState();
643 
644             if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
645                 // This is retry after failure over IMS but voice is not available.
646                 // Set retry to max allowed, so no retry is sent and
647                 //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.
648                 tracker.mRetryCount = MAX_SEND_RETRIES;
649 
650                 Rlog.d(TAG, "handleSendComplete: Skipping retry: "
651                 +" isIms()="+isIms()
652                 +" mRetryCount="+tracker.mRetryCount
653                 +" mImsRetry="+tracker.mImsRetry
654                 +" mMessageRef="+tracker.mMessageRef
655                 +" SS= "+mPhone.getServiceState().getState());
656             }
657 
658             // if sms over IMS is not supported on data and voice is not available...
659             if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
660                 tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
661             } else if ((((CommandException)(ar.exception)).getCommandError()
662                     == CommandException.Error.SMS_FAIL_RETRY) &&
663                    tracker.mRetryCount < MAX_SEND_RETRIES) {
664                 // Retry after a delay if needed.
665                 // TODO: According to TS 23.040, 9.2.3.6, we should resend
666                 //       with the same TP-MR as the failed message, and
667                 //       TP-RD set to 1.  However, we don't have a means of
668                 //       knowing the MR for the failed message (EF_SMSstatus
669                 //       may or may not have the MR corresponding to this
670                 //       message, depending on the failure).  Also, in some
671                 //       implementations this retry is handled by the baseband.
672                 tracker.mRetryCount++;
673                 Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
674                 sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
675             } else {
676                 int errorCode = 0;
677                 if (ar.result != null) {
678                     errorCode = ((SmsResponse)ar.result).mErrorCode;
679                 }
680                 int error = RESULT_ERROR_GENERIC_FAILURE;
681                 if (((CommandException)(ar.exception)).getCommandError()
682                         == CommandException.Error.FDN_CHECK_FAILURE) {
683                     error = RESULT_ERROR_FDN_CHECK_FAILURE;
684                 }
685                 tracker.onFailed(mContext, error, errorCode);
686             }
687         }
688     }
689 
690     /**
691      * Handles outbound message when the phone is not in service.
692      *
693      * @param ss     Current service state.  Valid values are:
694      *                  OUT_OF_SERVICE
695      *                  EMERGENCY_ONLY
696      *                  POWER_OFF
697      * @param sentIntent the PendingIntent to send the error to
698      */
handleNotInService(int ss, PendingIntent sentIntent)699     protected static void handleNotInService(int ss, PendingIntent sentIntent) {
700         if (sentIntent != null) {
701             try {
702                 if (ss == ServiceState.STATE_POWER_OFF) {
703                     sentIntent.send(RESULT_ERROR_RADIO_OFF);
704                 } else {
705                     sentIntent.send(RESULT_ERROR_NO_SERVICE);
706                 }
707             } catch (CanceledException ex) {}
708         }
709     }
710 
711     /**
712      * @param ss service state
713      * @return The result error based on input service state for not in service error
714      */
getNotInServiceError(int ss)715     protected static int getNotInServiceError(int ss) {
716         if (ss == ServiceState.STATE_POWER_OFF) {
717             return RESULT_ERROR_RADIO_OFF;
718         }
719         return RESULT_ERROR_NO_SERVICE;
720     }
721 
722     /**
723      * Send a data based SMS to a specific application port.
724      *
725      * @param destAddr the address to send the message to
726      * @param scAddr is the service center address or null to use
727      *  the current default SMSC
728      * @param destPort the port to deliver the message to
729      * @param data the body of the message to send
730      * @param sentIntent if not NULL this <code>PendingIntent</code> is
731      *  broadcast when the message is successfully sent, or failed.
732      *  The result code will be <code>Activity.RESULT_OK<code> for success,
733      *  or one of these errors:<br>
734      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
735      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
736      *  <code>RESULT_ERROR_NULL_PDU</code><br>
737      *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
738      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
739      *  the extra "errorCode" containing a radio technology specific value,
740      *  generally only useful for troubleshooting.<br>
741      *  The per-application based SMS control checks sentIntent. If sentIntent
742      *  is NULL the caller will be checked against all unknown applications,
743      *  which cause smaller number of SMS to be sent in checking period.
744      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
745      *  broadcast when the message is delivered to the recipient.  The
746      *  raw pdu of the status report is in the extended data ("pdu").
747      */
sendData(String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)748     protected abstract void sendData(String destAddr, String scAddr, int destPort,
749             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent);
750 
751     /**
752      * Send a text based SMS.
753      *  @param destAddr the address to send the message to
754      * @param scAddr is the service center address or null to use
755      *  the current default SMSC
756      * @param text the body of the message to send
757      * @param sentIntent if not NULL this <code>PendingIntent</code> is
758      *  broadcast when the message is successfully sent, or failed.
759      *  The result code will be <code>Activity.RESULT_OK<code> for success,
760      *  or one of these errors:<br>
761      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
762      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
763      *  <code>RESULT_ERROR_NULL_PDU</code><br>
764      *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
765      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
766      *  the extra "errorCode" containing a radio technology specific value,
767      *  generally only useful for troubleshooting.<br>
768      *  The per-application based SMS control checks sentIntent. If sentIntent
769      *  is NULL the caller will be checked against all unknown applications,
770      *  which cause smaller number of SMS to be sent in checking period.
771      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
772      *  broadcast when the message is delivered to the recipient.  The
773      * @param messageUri optional URI of the message if it is already stored in the system
774      * @param callingPkg the calling package name
775      * @param persistMessage whether to save the sent message into SMS DB for a
776      *   non-default SMS app.
777      */
sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage)778     protected abstract void sendText(String destAddr, String scAddr, String text,
779             PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri,
780             String callingPkg, boolean persistMessage);
781 
782     /**
783      * Inject an SMS PDU into the android platform.
784      *
785      * @param pdu is the byte array of pdu to be injected into android telephony layer
786      * @param format is the format of SMS pdu (3gpp or 3gpp2)
787      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
788      *  broadcast when the message is successfully received by the
789      *  android telephony layer. This intent is broadcasted at
790      *  the same time an SMS received from radio is responded back.
791      */
injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent)792     protected abstract void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent);
793 
794     /**
795      * Calculate the number of septets needed to encode the message. This function should only be
796      * called for individual segments of multipart message.
797      *
798      * @param messageBody the message to encode
799      * @param use7bitOnly ignore (but still count) illegal characters if true
800      * @return TextEncodingDetails
801      */
calculateLength(CharSequence messageBody, boolean use7bitOnly)802     protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
803             boolean use7bitOnly);
804 
805     /**
806      * Send a multi-part text based SMS.
807      *  @param destAddr the address to send the message to
808      * @param scAddr is the service center address or null to use
809      *   the current default SMSC
810      * @param parts an <code>ArrayList</code> of strings that, in order,
811      *   comprise the original message
812      * @param sentIntents if not null, an <code>ArrayList</code> of
813      *   <code>PendingIntent</code>s (one for each message part) that is
814      *   broadcast when the corresponding message part has been sent.
815      *   The result code will be <code>Activity.RESULT_OK<code> for success,
816      *   or one of these errors:
817      *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
818      *   <code>RESULT_ERROR_RADIO_OFF</code>
819      *   <code>RESULT_ERROR_NULL_PDU</code>
820      *   <code>RESULT_ERROR_NO_SERVICE</code>.
821      *  The per-application based SMS control checks sentIntent. If sentIntent
822      *  is NULL the caller will be checked against all unknown applications,
823      *  which cause smaller number of SMS to be sent in checking period.
824      * @param deliveryIntents if not null, an <code>ArrayList</code> of
825      *   <code>PendingIntent</code>s (one for each message part) that is
826      *   broadcast when the corresponding message part has been delivered
827      *   to the recipient.  The raw pdu of the status report is in the
828      * @param messageUri optional URI of the message if it is already stored in the system
829      * @param callingPkg the calling package name
830      * @param persistMessage whether to save the sent message into SMS DB for a
831      *   non-default SMS app.
832      */
sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage)833     protected void sendMultipartText(String destAddr, String scAddr,
834             ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
835             ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
836             boolean persistMessage) {
837         final String fullMessageText = getMultipartMessageText(parts);
838         int refNumber = getNextConcatenatedRef() & 0x00FF;
839         int msgCount = parts.size();
840         int encoding = SmsConstants.ENCODING_UNKNOWN;
841 
842         TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
843         for (int i = 0; i < msgCount; i++) {
844             TextEncodingDetails details = calculateLength(parts.get(i), false);
845             if (encoding != details.codeUnitSize
846                     && (encoding == SmsConstants.ENCODING_UNKNOWN
847                             || encoding == SmsConstants.ENCODING_7BIT)) {
848                 encoding = details.codeUnitSize;
849             }
850             encodingForParts[i] = details;
851         }
852 
853         SmsTracker[] trackers = new SmsTracker[msgCount];
854 
855         // States to track at the message level (for all parts)
856         final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
857         final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
858 
859         for (int i = 0; i < msgCount; i++) {
860             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
861             concatRef.refNumber = refNumber;
862             concatRef.seqNumber = i + 1;  // 1-based sequence
863             concatRef.msgCount = msgCount;
864             // TODO: We currently set this to true since our messaging app will never
865             // send more than 255 parts (it converts the message to MMS well before that).
866             // However, we should support 3rd party messaging apps that might need 16-bit
867             // references
868             // Note:  It's not sufficient to just flip this bit to true; it will have
869             // ripple effects (several calculations assume 8-bit ref).
870             concatRef.isEightBits = true;
871             SmsHeader smsHeader = new SmsHeader();
872             smsHeader.concatRef = concatRef;
873 
874             // Set the national language tables for 3GPP 7-bit encoding, if enabled.
875             if (encoding == SmsConstants.ENCODING_7BIT) {
876                 smsHeader.languageTable = encodingForParts[i].languageTable;
877                 smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
878             }
879 
880             PendingIntent sentIntent = null;
881             if (sentIntents != null && sentIntents.size() > i) {
882                 sentIntent = sentIntents.get(i);
883             }
884 
885             PendingIntent deliveryIntent = null;
886             if (deliveryIntents != null && deliveryIntents.size() > i) {
887                 deliveryIntent = deliveryIntents.get(i);
888             }
889 
890             trackers[i] =
891                 getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding,
892                         sentIntent, deliveryIntent, (i == (msgCount - 1)),
893                         unsentPartCount, anyPartFailed, messageUri, fullMessageText);
894             trackers[i].mPersistMessage = persistMessage;
895         }
896 
897         if (parts == null || trackers == null || trackers.length == 0
898                 || trackers[0] == null) {
899             Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers);
900             return;
901         }
902 
903         String carrierPackage = getCarrierAppPackageName();
904         if (carrierPackage != null) {
905             Rlog.d(TAG, "Found carrier package.");
906             MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
907             smsSender.sendSmsByCarrierApp(carrierPackage, new MultipartSmsSenderCallback(smsSender));
908         } else {
909             Rlog.v(TAG, "No carrier package.");
910             for (SmsTracker tracker : trackers) {
911                 if (tracker != null) {
912                     sendSubmitPdu(tracker);
913                 } else {
914                     Rlog.e(TAG, "Null tracker.");
915                 }
916             }
917         }
918     }
919 
920     /**
921      * Create a new SubmitPdu and return the SMS tracker.
922      */
getNewSubmitPduTracker(String destinationAddress, String scAddress, String message, SmsHeader smsHeader, int encoding, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, String fullMessageText)923     protected abstract SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
924             String message, SmsHeader smsHeader, int encoding,
925             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
926             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
927             String fullMessageText);
928 
929     /**
930      * Send an SMS
931      * @param tracker will contain:
932      * -smsc the SMSC to send the message through, or NULL for the
933      *  default SMSC
934      * -pdu the raw PDU to send
935      * -sentIntent if not NULL this <code>Intent</code> is
936      *  broadcast when the message is successfully sent, or failed.
937      *  The result code will be <code>Activity.RESULT_OK<code> for success,
938      *  or one of these errors:
939      *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
940      *  <code>RESULT_ERROR_RADIO_OFF</code>
941      *  <code>RESULT_ERROR_NULL_PDU</code>
942      *  <code>RESULT_ERROR_NO_SERVICE</code>.
943      *  The per-application based SMS control checks sentIntent. If sentIntent
944      *  is NULL the caller will be checked against all unknown applications,
945      *  which cause smaller number of SMS to be sent in checking period.
946      * -deliveryIntent if not NULL this <code>Intent</code> is
947      *  broadcast when the message is delivered to the recipient.  The
948      *  raw pdu of the status report is in the extended data ("pdu").
949      * -param destAddr the destination phone number (for short code confirmation)
950      */
sendRawPdu(SmsTracker tracker)951     protected void sendRawPdu(SmsTracker tracker) {
952         HashMap map = tracker.getData();
953         byte pdu[] = (byte[]) map.get("pdu");
954 
955         if (mSmsSendDisabled) {
956             Rlog.e(TAG, "Device does not support sending sms.");
957             tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
958             return;
959         }
960 
961         if (pdu == null) {
962             Rlog.e(TAG, "Empty PDU");
963             tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);
964             return;
965         }
966 
967         // Get calling app package name via UID from Binder call
968         PackageManager pm = mContext.getPackageManager();
969         String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
970 
971         if (packageNames == null || packageNames.length == 0) {
972             // Refuse to send SMS if we can't get the calling package name.
973             Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");
974             tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
975             return;
976         }
977 
978         // Get package info via packagemanager
979         PackageInfo appInfo;
980         try {
981             // XXX this is lossy- apps can share a UID
982             appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
983         } catch (PackageManager.NameNotFoundException e) {
984             Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
985             tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
986             return;
987         }
988 
989         // checkDestination() returns true if the destination is not a premium short code or the
990         // sending app is approved to send to short codes. Otherwise, a message is sent to our
991         // handler with the SmsTracker to request user confirmation before sending.
992         if (checkDestination(tracker)) {
993             // check for excessive outgoing SMS usage by this app
994             if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
995                 sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
996                 return;
997             }
998 
999             sendSms(tracker);
1000         }
1001 
1002         if (PhoneNumberUtils.isLocalEmergencyNumber(mContext, tracker.mDestAddress)) {
1003             new AsyncEmergencyContactNotifier(mContext).execute();
1004         }
1005     }
1006 
1007     /**
1008      * Check if destination is a potential premium short code and sender is not pre-approved to
1009      * send to short codes.
1010      *
1011      * @param tracker the tracker for the SMS to send
1012      * @return true if the destination is approved; false if user confirmation event was sent
1013      */
checkDestination(SmsTracker tracker)1014     boolean checkDestination(SmsTracker tracker) {
1015         if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION)
1016                 == PackageManager.PERMISSION_GRANTED) {
1017             return true;            // app is pre-approved to send to short codes
1018         } else {
1019             int rule = mPremiumSmsRule.get();
1020             int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
1021             if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
1022                 String simCountryIso = mTelephonyManager.getSimCountryIso();
1023                 if (simCountryIso == null || simCountryIso.length() != 2) {
1024                     Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso");
1025                     simCountryIso = mTelephonyManager.getNetworkCountryIso();
1026                 }
1027 
1028                 smsCategory = mUsageMonitor.checkDestination(tracker.mDestAddress, simCountryIso);
1029             }
1030             if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
1031                 String networkCountryIso = mTelephonyManager.getNetworkCountryIso();
1032                 if (networkCountryIso == null || networkCountryIso.length() != 2) {
1033                     Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso");
1034                     networkCountryIso = mTelephonyManager.getSimCountryIso();
1035                 }
1036 
1037                 smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory,
1038                         mUsageMonitor.checkDestination(tracker.mDestAddress, networkCountryIso));
1039             }
1040 
1041             if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE
1042                     || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE
1043                     || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) {
1044                 return true;    // not a premium short code
1045             }
1046 
1047             // Do not allow any premium sms during SuW
1048             if (Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
1049                 Rlog.e(TAG, "Can't send premium sms during Setup Wizard");
1050                 return false;
1051             }
1052 
1053             // Wait for user confirmation unless the user has set permission to always allow/deny
1054             int premiumSmsPermission = mUsageMonitor.getPremiumSmsPermission(
1055                     tracker.mAppInfo.packageName);
1056             if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
1057                 // First time trying to send to premium SMS.
1058                 premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
1059             }
1060 
1061             switch (premiumSmsPermission) {
1062                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
1063                     Rlog.d(TAG, "User approved this app to send to premium SMS");
1064                     return true;
1065 
1066                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
1067                     Rlog.w(TAG, "User denied this app from sending to premium SMS");
1068                     sendMessage(obtainMessage(EVENT_STOP_SENDING, tracker));
1069                     return false;   // reject this message
1070 
1071                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
1072                 default:
1073                     int event;
1074                     if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
1075                         event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
1076                     } else {
1077                         event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
1078                     }
1079                     sendMessage(obtainMessage(event, tracker));
1080                     return false;   // wait for user confirmation
1081             }
1082         }
1083     }
1084 
1085     /**
1086      * Deny sending an SMS if the outgoing queue limit is reached. Used when the message
1087      * must be confirmed by the user due to excessive usage or potential premium SMS detected.
1088      * @param tracker the SmsTracker for the message to send
1089      * @return true if the message was denied; false to continue with send confirmation
1090      */
denyIfQueueLimitReached(SmsTracker tracker)1091     private boolean denyIfQueueLimitReached(SmsTracker tracker) {
1092         if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
1093             // Deny sending message when the queue limit is reached.
1094             Rlog.e(TAG, "Denied because queue limit reached");
1095             tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
1096             return true;
1097         }
1098         mPendingTrackerCount++;
1099         return false;
1100     }
1101 
1102     /**
1103      * Returns the label for the specified app package name.
1104      * @param appPackage the package name of the app requesting to send an SMS
1105      * @return the label for the specified app, or the package name if getApplicationInfo() fails
1106      */
getAppLabel(String appPackage)1107     private CharSequence getAppLabel(String appPackage) {
1108         PackageManager pm = mContext.getPackageManager();
1109         try {
1110             ApplicationInfo appInfo = pm.getApplicationInfo(appPackage, 0);
1111             return appInfo.loadSafeLabel(pm);
1112         } catch (PackageManager.NameNotFoundException e) {
1113             Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
1114             return appPackage;  // fall back to package name if we can't get app label
1115         }
1116     }
1117 
1118     /**
1119      * Post an alert when SMS needs confirmation due to excessive usage.
1120      * @param tracker an SmsTracker for the current message.
1121      */
handleReachSentLimit(SmsTracker tracker)1122     protected void handleReachSentLimit(SmsTracker tracker) {
1123         if (denyIfQueueLimitReached(tracker)) {
1124             return;     // queue limit reached; error was returned to caller
1125         }
1126 
1127         CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
1128         Resources r = Resources.getSystem();
1129         Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
1130 
1131         ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null);
1132 
1133         AlertDialog d = new AlertDialog.Builder(mContext)
1134                 .setTitle(R.string.sms_control_title)
1135                 .setIcon(R.drawable.stat_sys_warning)
1136                 .setMessage(messageText)
1137                 .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
1138                 .setNegativeButton(r.getString(R.string.sms_control_no), listener)
1139                 .setOnCancelListener(listener)
1140                 .create();
1141 
1142         d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1143         d.show();
1144     }
1145 
1146     /**
1147      * Post an alert for user confirmation when sending to a potential short code.
1148      * @param isPremium true if the destination is known to be a premium short code
1149      * @param tracker the SmsTracker for the current message.
1150      */
handleConfirmShortCode(boolean isPremium, SmsTracker tracker)1151     protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) {
1152         if (denyIfQueueLimitReached(tracker)) {
1153             return;     // queue limit reached; error was returned to caller
1154         }
1155 
1156         int detailsId;
1157         if (isPremium) {
1158             detailsId = R.string.sms_premium_short_code_details;
1159         } else {
1160             detailsId = R.string.sms_short_code_details;
1161         }
1162 
1163         CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
1164         Resources r = Resources.getSystem();
1165         Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
1166                 appLabel, tracker.mDestAddress));
1167 
1168         LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
1169                 Context.LAYOUT_INFLATER_SERVICE);
1170         View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
1171 
1172         ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
1173                 (TextView)layout.findViewById(R.id.sms_short_code_remember_undo_instruction));
1174 
1175 
1176         TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
1177         messageView.setText(messageText);
1178 
1179         ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
1180                 R.id.sms_short_code_detail_layout);
1181         TextView detailsView = (TextView) detailsLayout.findViewById(
1182                 R.id.sms_short_code_detail_message);
1183         detailsView.setText(detailsId);
1184 
1185         CheckBox rememberChoice = (CheckBox) layout.findViewById(
1186                 R.id.sms_short_code_remember_choice_checkbox);
1187         rememberChoice.setOnCheckedChangeListener(listener);
1188 
1189         AlertDialog d = new AlertDialog.Builder(mContext)
1190                 .setView(layout)
1191                 .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
1192                 .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
1193                 .setOnCancelListener(listener)
1194                 .create();
1195 
1196         d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1197         d.show();
1198 
1199         listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
1200         listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
1201     }
1202 
1203     /**
1204      * Returns the premium SMS permission for the specified package. If the package has never
1205      * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}
1206      * will be returned.
1207      * @param packageName the name of the package to query permission
1208      * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
1209      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
1210      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
1211      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
1212      */
getPremiumSmsPermission(String packageName)1213     public int getPremiumSmsPermission(String packageName) {
1214         return mUsageMonitor.getPremiumSmsPermission(packageName);
1215     }
1216 
1217     /**
1218      * Sets the premium SMS permission for the specified package and save the value asynchronously
1219      * to persistent storage.
1220      * @param packageName the name of the package to set permission
1221      * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
1222      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
1223      *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
1224      */
setPremiumSmsPermission(String packageName, int permission)1225     public void setPremiumSmsPermission(String packageName, int permission) {
1226         mUsageMonitor.setPremiumSmsPermission(packageName, permission);
1227     }
1228 
1229     /**
1230      * Send the message along to the radio.
1231      *
1232      * @param tracker holds the SMS message to send
1233      */
sendSms(SmsTracker tracker)1234     protected abstract void sendSms(SmsTracker tracker);
1235 
1236     /**
1237      * Send the SMS via the PSTN network.
1238      *
1239      * @param tracker holds the Sms tracker ready to be sent
1240      */
sendSmsByPstn(SmsTracker tracker)1241     protected abstract void sendSmsByPstn(SmsTracker tracker);
1242 
1243     /**
1244      * Retry the message along to the radio.
1245      *
1246      * @param tracker holds the SMS message to send
1247      */
sendRetrySms(SmsTracker tracker)1248     public void sendRetrySms(SmsTracker tracker) {
1249         // re-routing to ImsSMSDispatcher
1250         if (mImsSMSDispatcher != null) {
1251             mImsSMSDispatcher.sendRetrySms(tracker);
1252         } else {
1253             Rlog.e(TAG, mImsSMSDispatcher + " is null. Retry failed");
1254         }
1255     }
1256 
1257     /**
1258      * Send the multi-part SMS based on multipart Sms tracker
1259      *
1260      * @param tracker holds the multipart Sms tracker ready to be sent
1261      */
sendMultipartSms(SmsTracker tracker)1262     private void sendMultipartSms(SmsTracker tracker) {
1263         ArrayList<String> parts;
1264         ArrayList<PendingIntent> sentIntents;
1265         ArrayList<PendingIntent> deliveryIntents;
1266 
1267         HashMap<String, Object> map = tracker.getData();
1268 
1269         String destinationAddress = (String) map.get("destination");
1270         String scAddress = (String) map.get("scaddress");
1271 
1272         parts = (ArrayList<String>) map.get("parts");
1273         sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
1274         deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
1275 
1276         // check if in service
1277         int ss = mPhone.getServiceState().getState();
1278         // if sms over IMS is not supported on data and voice is not available...
1279         if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
1280             for (int i = 0, count = parts.size(); i < count; i++) {
1281                 PendingIntent sentIntent = null;
1282                 if (sentIntents != null && sentIntents.size() > i) {
1283                     sentIntent = sentIntents.get(i);
1284                 }
1285                 handleNotInService(ss, sentIntent);
1286             }
1287             return;
1288         }
1289 
1290         sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents,
1291                 null/*messageUri*/, null/*callingPkg*/, tracker.mPersistMessage);
1292     }
1293 
1294     /**
1295      * Keeps track of an SMS that has been sent to the RIL, until it has
1296      * successfully been sent, or we're done trying.
1297      */
1298     public static class SmsTracker {
1299         // fields need to be public for derived SmsDispatchers
1300         private final HashMap<String, Object> mData;
1301         public int mRetryCount;
1302         public int mImsRetry; // nonzero indicates initial message was sent over Ims
1303         public int mMessageRef;
1304         public boolean mExpectMore;
1305         String mFormat;
1306 
1307         public final PendingIntent mSentIntent;
1308         public final PendingIntent mDeliveryIntent;
1309 
1310         public final PackageInfo mAppInfo;
1311         public final String mDestAddress;
1312 
1313         public final SmsHeader mSmsHeader;
1314 
1315         private long mTimestamp = System.currentTimeMillis();
1316         public Uri mMessageUri; // Uri of persisted message if we wrote one
1317 
1318         // Reference to states of a multipart message that this part belongs to
1319         private AtomicInteger mUnsentPartCount;
1320         private AtomicBoolean mAnyPartFailed;
1321         // The full message content of a single part message
1322         // or a multipart message that this part belongs to
1323         private String mFullMessageText;
1324 
1325         private int mSubId;
1326 
1327         // If this is a text message (instead of data message)
1328         private boolean mIsText;
1329 
1330         private boolean mPersistMessage;
1331 
SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader, boolean isExpectMore, String fullMessageText, int subId, boolean isText, boolean persistMessage)1332         private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1333                 PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format,
1334                 AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
1335                 SmsHeader smsHeader, boolean isExpectMore, String fullMessageText, int subId,
1336                 boolean isText, boolean persistMessage) {
1337             mData = data;
1338             mSentIntent = sentIntent;
1339             mDeliveryIntent = deliveryIntent;
1340             mRetryCount = 0;
1341             mAppInfo = appInfo;
1342             mDestAddress = destAddr;
1343             mFormat = format;
1344             mExpectMore = isExpectMore;
1345             mImsRetry = 0;
1346             mMessageRef = 0;
1347             mUnsentPartCount = unsentPartCount;
1348             mAnyPartFailed = anyPartFailed;
1349             mMessageUri = messageUri;
1350             mSmsHeader = smsHeader;
1351             mFullMessageText = fullMessageText;
1352             mSubId = subId;
1353             mIsText = isText;
1354             mPersistMessage = persistMessage;
1355         }
1356 
1357         /**
1358          * Returns whether this tracker holds a multi-part SMS.
1359          * @return true if the tracker holds a multi-part SMS; false otherwise
1360          */
isMultipart()1361         boolean isMultipart() {
1362             return mData.containsKey("parts");
1363         }
1364 
getData()1365         public HashMap<String, Object> getData() {
1366             return mData;
1367         }
1368 
1369         /**
1370          * Update the status of this message if we persisted it
1371          */
updateSentMessageStatus(Context context, int status)1372         public void updateSentMessageStatus(Context context, int status) {
1373             if (mMessageUri != null) {
1374                 // If we wrote this message in writeSentMessage, update it now
1375                 ContentValues values = new ContentValues(1);
1376                 values.put(Sms.STATUS, status);
1377                 SqliteWrapper.update(context, context.getContentResolver(),
1378                         mMessageUri, values, null, null);
1379             }
1380         }
1381 
1382         /**
1383          * Set the final state of a message: FAILED or SENT
1384          *
1385          * @param context The Context
1386          * @param messageType The final message type
1387          * @param errorCode The error code
1388          */
updateMessageState(Context context, int messageType, int errorCode)1389         private void updateMessageState(Context context, int messageType, int errorCode) {
1390             if (mMessageUri == null) {
1391                 return;
1392             }
1393             final ContentValues values = new ContentValues(2);
1394             values.put(Sms.TYPE, messageType);
1395             values.put(Sms.ERROR_CODE, errorCode);
1396             final long identity = Binder.clearCallingIdentity();
1397             try {
1398                 if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
1399                         null/*where*/, null/*selectionArgs*/) != 1) {
1400                     Rlog.e(TAG, "Failed to move message to " + messageType);
1401                 }
1402             } finally {
1403                 Binder.restoreCallingIdentity(identity);
1404             }
1405         }
1406 
1407         /**
1408          * Persist a sent SMS if required:
1409          * 1. It is a text message
1410          * 2. SmsApplication tells us to persist: sent from apps that are not default-SMS app or
1411          *    bluetooth
1412          *
1413          * @param context
1414          * @param messageType The folder to store (FAILED or SENT)
1415          * @param errorCode The current error code for this SMS or SMS part
1416          * @return The telephony provider URI if stored
1417          */
persistSentMessageIfRequired(Context context, int messageType, int errorCode)1418         private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) {
1419             if (!mIsText || !mPersistMessage ||
1420                     !SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) {
1421                 return null;
1422             }
1423             Rlog.d(TAG, "Persist SMS into "
1424                     + (messageType == Sms.MESSAGE_TYPE_FAILED ? "FAILED" : "SENT"));
1425             final ContentValues values = new ContentValues();
1426             values.put(Sms.SUBSCRIPTION_ID, mSubId);
1427             values.put(Sms.ADDRESS, mDestAddress);
1428             values.put(Sms.BODY, mFullMessageText);
1429             values.put(Sms.DATE, System.currentTimeMillis()); // milliseconds
1430             values.put(Sms.SEEN, 1);
1431             values.put(Sms.READ, 1);
1432             final String creator = mAppInfo != null ? mAppInfo.packageName : null;
1433             if (!TextUtils.isEmpty(creator)) {
1434                 values.put(Sms.CREATOR, creator);
1435             }
1436             if (mDeliveryIntent != null) {
1437                 values.put(Sms.STATUS, Telephony.Sms.STATUS_PENDING);
1438             }
1439             if (errorCode != 0) {
1440                 values.put(Sms.ERROR_CODE, errorCode);
1441             }
1442             final long identity = Binder.clearCallingIdentity();
1443             final ContentResolver resolver = context.getContentResolver();
1444             try {
1445                 final Uri uri =  resolver.insert(Telephony.Sms.Sent.CONTENT_URI, values);
1446                 if (uri != null && messageType == Sms.MESSAGE_TYPE_FAILED) {
1447                     // Since we can't persist a message directly into FAILED box,
1448                     // we have to update the column after we persist it into SENT box.
1449                     // The gap between the state change is tiny so I would not expect
1450                     // it to cause any serious problem
1451                     // TODO: we should add a "failed" URI for this in SmsProvider?
1452                     final ContentValues updateValues = new ContentValues(1);
1453                     updateValues.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
1454                     resolver.update(uri, updateValues, null/*where*/, null/*selectionArgs*/);
1455                 }
1456                 return uri;
1457             } catch (Exception e) {
1458                 Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
1459                 return null;
1460             } finally {
1461                 Binder.restoreCallingIdentity(identity);
1462             }
1463         }
1464 
1465         /**
1466          * Persist or update an SMS depending on if we send a new message or a stored message
1467          *
1468          * @param context
1469          * @param messageType The message folder for this SMS, FAILED or SENT
1470          * @param errorCode The current error code for this SMS or SMS part
1471          */
persistOrUpdateMessage(Context context, int messageType, int errorCode)1472         private void persistOrUpdateMessage(Context context, int messageType, int errorCode) {
1473             if (mMessageUri != null) {
1474                 updateMessageState(context, messageType, errorCode);
1475             } else {
1476                 mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode);
1477             }
1478         }
1479 
1480         /**
1481          * Handle a failure of a single part message or a part of a multipart message
1482          *
1483          * @param context The Context
1484          * @param error The error to send back with
1485          * @param errorCode
1486          */
onFailed(Context context, int error, int errorCode)1487         public void onFailed(Context context, int error, int errorCode) {
1488             if (mAnyPartFailed != null) {
1489                 mAnyPartFailed.set(true);
1490             }
1491             // is single part or last part of multipart message
1492             boolean isSinglePartOrLastPart = true;
1493             if (mUnsentPartCount != null) {
1494                 isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1495             }
1496             if (isSinglePartOrLastPart) {
1497                 persistOrUpdateMessage(context, Sms.MESSAGE_TYPE_FAILED, errorCode);
1498             }
1499             if (mSentIntent != null) {
1500                 try {
1501                     // Extra information to send with the sent intent
1502                     Intent fillIn = new Intent();
1503                     if (mMessageUri != null) {
1504                         // Pass this to SMS apps so that they know where it is stored
1505                         fillIn.putExtra("uri", mMessageUri.toString());
1506                     }
1507                     if (errorCode != 0) {
1508                         fillIn.putExtra("errorCode", errorCode);
1509                     }
1510                     if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1511                         // Is multipart and last part
1512                         fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1513                     }
1514                     mSentIntent.send(context, error, fillIn);
1515                 } catch (CanceledException ex) {
1516                     Rlog.e(TAG, "Failed to send result");
1517                 }
1518             }
1519         }
1520 
1521         /**
1522          * Handle the sent of a single part message or a part of a multipart message
1523          *
1524          * @param context The Context
1525          */
onSent(Context context)1526         public void onSent(Context context) {
1527             // is single part or last part of multipart message
1528             boolean isSinglePartOrLastPart = true;
1529             if (mUnsentPartCount != null) {
1530                 isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1531             }
1532             if (isSinglePartOrLastPart) {
1533                 int messageType = Sms.MESSAGE_TYPE_SENT;
1534                 if (mAnyPartFailed != null && mAnyPartFailed.get()) {
1535                     messageType = Sms.MESSAGE_TYPE_FAILED;
1536                 }
1537                 persistOrUpdateMessage(context, messageType, 0/*errorCode*/);
1538             }
1539             if (mSentIntent != null) {
1540                 try {
1541                     // Extra information to send with the sent intent
1542                     Intent fillIn = new Intent();
1543                     if (mMessageUri != null) {
1544                         // Pass this to SMS apps so that they know where it is stored
1545                         fillIn.putExtra("uri", mMessageUri.toString());
1546                     }
1547                     if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1548                         // Is multipart and last part
1549                         fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1550                     }
1551                     mSentIntent.send(context, Activity.RESULT_OK, fillIn);
1552                 } catch (CanceledException ex) {
1553                     Rlog.e(TAG, "Failed to send result");
1554                 }
1555             }
1556         }
1557     }
1558 
getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader, boolean isExpectMore, String fullMessageText, boolean isText, boolean persistMessage)1559     protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1560             PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount,
1561             AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader,
1562             boolean isExpectMore, String fullMessageText, boolean isText, boolean persistMessage) {
1563         // Get calling app package name via UID from Binder call
1564         PackageManager pm = mContext.getPackageManager();
1565         String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
1566 
1567         // Get package info via packagemanager
1568         PackageInfo appInfo = null;
1569         if (packageNames != null && packageNames.length > 0) {
1570             try {
1571                 // XXX this is lossy- apps can share a UID
1572                 appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
1573             } catch (PackageManager.NameNotFoundException e) {
1574                 // error will be logged in sendRawPdu
1575             }
1576         }
1577         // Strip non-digits from destination phone number before checking for short codes
1578         // and before displaying the number to the user if confirmation is required.
1579         String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
1580         return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format,
1581                 unsentPartCount, anyPartFailed, messageUri, smsHeader, isExpectMore,
1582                 fullMessageText, getSubId(), isText, persistMessage);
1583     }
1584 
getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent, String format, Uri messageUri, boolean isExpectMore, String fullMessageText, boolean isText, boolean persistMessage)1585     protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1586             PendingIntent deliveryIntent, String format, Uri messageUri, boolean isExpectMore,
1587             String fullMessageText, boolean isText, boolean persistMessage) {
1588         return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/,
1589                 null/*anyPartFailed*/, messageUri, null/*smsHeader*/, isExpectMore,
1590                 fullMessageText, isText, persistMessage);
1591     }
1592 
getSmsTrackerMap(String destAddr, String scAddr, String text, SmsMessageBase.SubmitPduBase pdu)1593     protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
1594             String text, SmsMessageBase.SubmitPduBase pdu) {
1595         HashMap<String, Object> map = new HashMap<String, Object>();
1596         map.put("destAddr", destAddr);
1597         map.put("scAddr", scAddr);
1598         map.put("text", text);
1599         map.put("smsc", pdu.encodedScAddress);
1600         map.put("pdu", pdu.encodedMessage);
1601         return map;
1602     }
1603 
getSmsTrackerMap(String destAddr, String scAddr, int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu)1604     protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
1605             int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
1606         HashMap<String, Object> map = new HashMap<String, Object>();
1607         map.put("destAddr", destAddr);
1608         map.put("scAddr", scAddr);
1609         map.put("destPort", destPort);
1610         map.put("data", data);
1611         map.put("smsc", pdu.encodedScAddress);
1612         map.put("pdu", pdu.encodedMessage);
1613         return map;
1614     }
1615 
1616     /**
1617      * Dialog listener for SMS confirmation dialog.
1618      */
1619     private final class ConfirmDialogListener
1620             implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
1621             CompoundButton.OnCheckedChangeListener {
1622 
1623         private final SmsTracker mTracker;
1624         private Button mPositiveButton;
1625         private Button mNegativeButton;
1626         private boolean mRememberChoice;    // default is unchecked
1627         private final TextView mRememberUndoInstruction;
1628 
ConfirmDialogListener(SmsTracker tracker, TextView textView)1629         ConfirmDialogListener(SmsTracker tracker, TextView textView) {
1630             mTracker = tracker;
1631             mRememberUndoInstruction = textView;
1632         }
1633 
setPositiveButton(Button button)1634         void setPositiveButton(Button button) {
1635             mPositiveButton = button;
1636         }
1637 
setNegativeButton(Button button)1638         void setNegativeButton(Button button) {
1639             mNegativeButton = button;
1640         }
1641 
1642         @Override
onClick(DialogInterface dialog, int which)1643         public void onClick(DialogInterface dialog, int which) {
1644             // Always set the SMS permission so that Settings will show a permission setting
1645             // for the app (it won't be shown until after the app tries to send to a short code).
1646             int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
1647 
1648             if (which == DialogInterface.BUTTON_POSITIVE) {
1649                 Rlog.d(TAG, "CONFIRM sending SMS");
1650                 // XXX this is lossy- apps can have more than one signature
1651                 EventLog.writeEvent(EventLogTags.EXP_DET_SMS_SENT_BY_USER,
1652                                     mTracker.mAppInfo.applicationInfo == null ?
1653                                     -1 : mTracker.mAppInfo.applicationInfo.uid);
1654                 sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker));
1655                 if (mRememberChoice) {
1656                     newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
1657                 }
1658             } else if (which == DialogInterface.BUTTON_NEGATIVE) {
1659                 Rlog.d(TAG, "DENY sending SMS");
1660                 // XXX this is lossy- apps can have more than one signature
1661                 EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
1662                                     mTracker.mAppInfo.applicationInfo == null ?
1663                                     -1 :  mTracker.mAppInfo.applicationInfo.uid);
1664                 sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
1665                 if (mRememberChoice) {
1666                     newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
1667                 }
1668             }
1669             setPremiumSmsPermission(mTracker.mAppInfo.packageName, newSmsPermission);
1670         }
1671 
1672         @Override
onCancel(DialogInterface dialog)1673         public void onCancel(DialogInterface dialog) {
1674             Rlog.d(TAG, "dialog dismissed: don't send SMS");
1675             sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
1676         }
1677 
1678         @Override
onCheckedChanged(CompoundButton buttonView, boolean isChecked)1679         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1680             Rlog.d(TAG, "remember this choice: " + isChecked);
1681             mRememberChoice = isChecked;
1682             if (isChecked) {
1683                 mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
1684                 mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
1685                 if (mRememberUndoInstruction != null) {
1686                     mRememberUndoInstruction.
1687                             setText(R.string.sms_short_code_remember_undo_instruction);
1688                     mRememberUndoInstruction.setPadding(0,0,0,32);
1689                 }
1690             } else {
1691                 mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
1692                 mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
1693                 if (mRememberUndoInstruction != null) {
1694                     mRememberUndoInstruction.setText("");
1695                     mRememberUndoInstruction.setPadding(0,0,0,0);
1696                 }
1697             }
1698         }
1699     }
1700 
isIms()1701     public boolean isIms() {
1702         if (mImsSMSDispatcher != null) {
1703             return mImsSMSDispatcher.isIms();
1704         } else {
1705             Rlog.e(TAG, mImsSMSDispatcher + " is null");
1706             return false;
1707         }
1708     }
1709 
getImsSmsFormat()1710     public String getImsSmsFormat() {
1711         if (mImsSMSDispatcher != null) {
1712             return mImsSMSDispatcher.getImsSmsFormat();
1713         } else {
1714             Rlog.e(TAG, mImsSMSDispatcher + " is null");
1715             return null;
1716         }
1717     }
1718 
getMultipartMessageText(ArrayList<String> parts)1719     private String getMultipartMessageText(ArrayList<String> parts) {
1720         final StringBuilder sb = new StringBuilder();
1721         for (String part : parts) {
1722             if (part != null) {
1723                 sb.append(part);
1724             }
1725         }
1726         return sb.toString();
1727     }
1728 
getCarrierAppPackageName()1729     protected String getCarrierAppPackageName() {
1730         UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
1731         if (card == null) {
1732             return null;
1733         }
1734 
1735         List<String> carrierPackages = card.getCarrierPackageNamesForIntent(
1736             mContext.getPackageManager(), new Intent(CarrierMessagingService.SERVICE_INTERFACE));
1737         return (carrierPackages != null && carrierPackages.size() == 1) ?
1738                 carrierPackages.get(0) : null;
1739     }
1740 
getSubId()1741     protected int getSubId() {
1742         return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.getPhoneId());
1743     }
1744 
checkCallerIsPhoneOrCarrierApp()1745     private void checkCallerIsPhoneOrCarrierApp() {
1746         int uid = Binder.getCallingUid();
1747         int appId = UserHandle.getAppId(uid);
1748         if (appId == Process.PHONE_UID || uid == 0) {
1749             return;
1750         }
1751         try {
1752             PackageManager pm = mContext.getPackageManager();
1753             ApplicationInfo ai = pm.getApplicationInfo(getCarrierAppPackageName(), 0);
1754             if (!UserHandle.isSameApp(ai.uid, Binder.getCallingUid())) {
1755                 throw new SecurityException("Caller is not phone or carrier app!");
1756             }
1757         } catch (PackageManager.NameNotFoundException re) {
1758             throw new SecurityException("Caller is not phone or carrier app!");
1759         }
1760     }
1761 }
1762