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