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