1/*
2 * Copyright (C) 2008 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;
18
19import static android.telephony.SmsManager.STATUS_ON_ICC_FREE;
20import static android.telephony.SmsManager.STATUS_ON_ICC_READ;
21import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD;
22
23import android.Manifest;
24import android.app.AppOpsManager;
25import android.app.PendingIntent;
26import android.content.ContentResolver;
27import android.content.Context;
28import android.content.Intent;
29import android.content.pm.PackageManager;
30import android.database.Cursor;
31import android.database.sqlite.SQLiteException;
32import android.net.Uri;
33import android.os.AsyncResult;
34import android.os.Binder;
35import android.os.Handler;
36import android.os.Message;
37import android.os.UserManager;
38import android.provider.Telephony;
39import android.service.carrier.CarrierMessagingService;
40import android.telephony.Rlog;
41import android.telephony.SmsManager;
42import android.telephony.SmsMessage;
43import android.util.Log;
44
45import com.android.internal.annotations.VisibleForTesting;
46import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
47import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
48import com.android.internal.telephony.uicc.IccConstants;
49import com.android.internal.telephony.uicc.IccFileHandler;
50import com.android.internal.telephony.uicc.IccUtils;
51import com.android.internal.util.HexDump;
52
53import java.util.ArrayList;
54import java.util.Arrays;
55import java.util.List;
56
57/**
58 * IccSmsInterfaceManager to provide an inter-process communication to
59 * access Sms in Icc.
60 */
61public class IccSmsInterfaceManager {
62    static final String LOG_TAG = "IccSmsInterfaceManager";
63    static final boolean DBG = true;
64
65    protected final Object mLock = new Object();
66    protected boolean mSuccess;
67    private List<SmsRawData> mSms;
68
69    private CellBroadcastRangeManager mCellBroadcastRangeManager =
70            new CellBroadcastRangeManager();
71    private CdmaBroadcastRangeManager mCdmaBroadcastRangeManager =
72            new CdmaBroadcastRangeManager();
73
74    private static final int EVENT_LOAD_DONE = 1;
75    private static final int EVENT_UPDATE_DONE = 2;
76    protected static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3;
77    protected static final int EVENT_SET_BROADCAST_CONFIG_DONE = 4;
78    private static final int SMS_CB_CODE_SCHEME_MIN = 0;
79    private static final int SMS_CB_CODE_SCHEME_MAX = 255;
80    public static final int SMS_MESSAGE_PRIORITY_NOT_SPECIFIED = -1;
81    public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1;
82
83    protected Phone mPhone;
84    final protected Context mContext;
85    final protected AppOpsManager mAppOps;
86    final private UserManager mUserManager;
87    protected SmsDispatchersController mDispatchersController;
88
89    protected Handler mHandler = new Handler() {
90        @Override
91        public void handleMessage(Message msg) {
92            AsyncResult ar;
93
94            switch (msg.what) {
95                case EVENT_UPDATE_DONE:
96                    ar = (AsyncResult) msg.obj;
97                    synchronized (mLock) {
98                        mSuccess = (ar.exception == null);
99                        mLock.notifyAll();
100                    }
101                    break;
102                case EVENT_LOAD_DONE:
103                    ar = (AsyncResult)msg.obj;
104                    synchronized (mLock) {
105                        if (ar.exception == null) {
106                            mSms = buildValidRawData((ArrayList<byte[]>) ar.result);
107                            //Mark SMS as read after importing it from card.
108                            markMessagesAsRead((ArrayList<byte[]>) ar.result);
109                        } else {
110                            if (Rlog.isLoggable("SMS", Log.DEBUG)) {
111                                log("Cannot load Sms records");
112                            }
113                            mSms = null;
114                        }
115                        mLock.notifyAll();
116                    }
117                    break;
118                case EVENT_SET_BROADCAST_ACTIVATION_DONE:
119                case EVENT_SET_BROADCAST_CONFIG_DONE:
120                    ar = (AsyncResult) msg.obj;
121                    synchronized (mLock) {
122                        mSuccess = (ar.exception == null);
123                        mLock.notifyAll();
124                    }
125                    break;
126            }
127        }
128    };
129
130    protected IccSmsInterfaceManager(Phone phone) {
131        this(phone, phone.getContext(),
132                (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE),
133                (UserManager) phone.getContext().getSystemService(Context.USER_SERVICE),
134                new SmsDispatchersController(
135                        phone, phone.mSmsStorageMonitor, phone.mSmsUsageMonitor));
136    }
137
138    @VisibleForTesting
139    public IccSmsInterfaceManager(
140            Phone phone, Context context, AppOpsManager appOps, UserManager userManager,
141            SmsDispatchersController dispatchersController) {
142        mPhone = phone;
143        mContext = context;
144        mAppOps = appOps;
145        mUserManager = userManager;
146        mDispatchersController = dispatchersController;
147    }
148
149    protected void markMessagesAsRead(ArrayList<byte[]> messages) {
150        if (messages == null) {
151            return;
152        }
153
154        //IccFileHandler can be null, if icc card is absent.
155        IccFileHandler fh = mPhone.getIccFileHandler();
156        if (fh == null) {
157            //shouldn't really happen, as messages are marked as read, only
158            //after importing it from icc.
159            if (Rlog.isLoggable("SMS", Log.DEBUG)) {
160                log("markMessagesAsRead - aborting, no icc card present.");
161            }
162            return;
163        }
164
165        int count = messages.size();
166
167        for (int i = 0; i < count; i++) {
168             byte[] ba = messages.get(i);
169             if (ba[0] == STATUS_ON_ICC_UNREAD) {
170                 int n = ba.length;
171                 byte[] nba = new byte[n - 1];
172                 System.arraycopy(ba, 1, nba, 0, n - 1);
173                 byte[] record = makeSmsRecordData(STATUS_ON_ICC_READ, nba);
174                 fh.updateEFLinearFixed(IccConstants.EF_SMS, i + 1, record, null, null);
175                 if (Rlog.isLoggable("SMS", Log.DEBUG)) {
176                     log("SMS " + (i + 1) + " marked as read");
177                 }
178             }
179        }
180    }
181
182    protected void updatePhoneObject(Phone phone) {
183        mPhone = phone;
184        mDispatchersController.updatePhoneObject(phone);
185    }
186
187    protected void enforceReceiveAndSend(String message) {
188        mContext.enforceCallingOrSelfPermission(
189                Manifest.permission.RECEIVE_SMS, message);
190        mContext.enforceCallingOrSelfPermission(
191                Manifest.permission.SEND_SMS, message);
192    }
193
194    /**
195     * Update the specified message on the Icc.
196     *
197     * @param index record index of message to update
198     * @param status new message status (STATUS_ON_ICC_READ,
199     *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
200     *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
201     * @param pdu the raw PDU to store
202     * @return success or not
203     *
204     */
205
206    public boolean
207    updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu) {
208        if (DBG) log("updateMessageOnIccEf: index=" + index +
209                " status=" + status + " ==> " +
210                "("+ Arrays.toString(pdu) + ")");
211        enforceReceiveAndSend("Updating message on Icc");
212        if (mAppOps.noteOp(AppOpsManager.OP_WRITE_ICC_SMS, Binder.getCallingUid(),
213                callingPackage) != AppOpsManager.MODE_ALLOWED) {
214            return false;
215        }
216        synchronized(mLock) {
217            mSuccess = false;
218            Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
219
220            if (status == STATUS_ON_ICC_FREE) {
221                // RIL_REQUEST_DELETE_SMS_ON_SIM vs RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM
222                // Special case FREE: call deleteSmsOnSim/Ruim instead of
223                // manipulating the record
224                // Will eventually fail if icc card is not present.
225                if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
226                    mPhone.mCi.deleteSmsOnSim(index, response);
227                } else {
228                    mPhone.mCi.deleteSmsOnRuim(index, response);
229                }
230            } else {
231                //IccFilehandler can be null if ICC card is not present.
232                IccFileHandler fh = mPhone.getIccFileHandler();
233                if (fh == null) {
234                    response.recycle();
235                    return mSuccess; /* is false */
236                }
237                byte[] record = makeSmsRecordData(status, pdu);
238                fh.updateEFLinearFixed(
239                        IccConstants.EF_SMS,
240                        index, record, null, response);
241            }
242            try {
243                mLock.wait();
244            } catch (InterruptedException e) {
245                log("interrupted while trying to update by index");
246            }
247        }
248        return mSuccess;
249    }
250
251    /**
252     * Copy a raw SMS PDU to the Icc.
253     *
254     * @param pdu the raw PDU to store
255     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
256     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
257     * @return success or not
258     *
259     */
260    public boolean copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc) {
261        //NOTE smsc not used in RUIM
262        if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " +
263                "pdu=("+ Arrays.toString(pdu) +
264                "), smsc=(" + Arrays.toString(smsc) +")");
265        enforceReceiveAndSend("Copying message to Icc");
266        if (mAppOps.noteOp(AppOpsManager.OP_WRITE_ICC_SMS, Binder.getCallingUid(),
267                callingPackage) != AppOpsManager.MODE_ALLOWED) {
268            return false;
269        }
270        synchronized(mLock) {
271            mSuccess = false;
272            Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
273
274            //RIL_REQUEST_WRITE_SMS_TO_SIM vs RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM
275            if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
276                mPhone.mCi.writeSmsToSim(status, IccUtils.bytesToHexString(smsc),
277                        IccUtils.bytesToHexString(pdu), response);
278            } else {
279                mPhone.mCi.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu),
280                        response);
281            }
282
283            try {
284                mLock.wait();
285            } catch (InterruptedException e) {
286                log("interrupted while trying to update by index");
287            }
288        }
289        return mSuccess;
290    }
291
292    /**
293     * Retrieves all messages currently stored on Icc.
294     *
295     * @return list of SmsRawData of all sms on Icc
296     */
297
298    public List<SmsRawData> getAllMessagesFromIccEf(String callingPackage) {
299        if (DBG) log("getAllMessagesFromEF");
300
301        mContext.enforceCallingOrSelfPermission(
302                Manifest.permission.RECEIVE_SMS,
303                "Reading messages from Icc");
304        if (mAppOps.noteOp(AppOpsManager.OP_READ_ICC_SMS, Binder.getCallingUid(),
305                callingPackage) != AppOpsManager.MODE_ALLOWED) {
306            return new ArrayList<SmsRawData>();
307        }
308        synchronized(mLock) {
309
310            IccFileHandler fh = mPhone.getIccFileHandler();
311            if (fh == null) {
312                Rlog.e(LOG_TAG, "Cannot load Sms records. No icc card?");
313                mSms = null;
314                return mSms;
315            }
316
317            Message response = mHandler.obtainMessage(EVENT_LOAD_DONE);
318            fh.loadEFLinearFixedAll(IccConstants.EF_SMS, response);
319
320            try {
321                mLock.wait();
322            } catch (InterruptedException e) {
323                log("interrupted while trying to load from the Icc");
324            }
325        }
326        return mSms;
327    }
328
329    /**
330     * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}.
331     * This method checks if the calling package or itself has the permission to send the data sms.
332     */
333    public void sendDataWithSelfPermissions(String callingPackage, String destAddr, String scAddr,
334            int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
335        if (!checkCallingOrSelfSendSmsPermission(callingPackage, "Sending SMS message")) {
336            return;
337        }
338        sendDataInternal(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent);
339    }
340
341    /**
342     * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}.
343     * This method checks only if the calling package has the permission to send the data sms.
344     */
345    public void sendData(String callingPackage, String destAddr, String scAddr, int destPort,
346            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
347        if (!checkCallingSendSmsPermission(callingPackage, "Sending SMS message")) {
348            return;
349        }
350        sendDataInternal(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent);
351    }
352
353    /**
354     * Send a data based SMS to a specific application port.
355     *
356     * @param destAddr the address to send the message to
357     * @param scAddr is the service center address or null to use
358     *  the current default SMSC
359     * @param destPort the port to deliver the message to
360     * @param data the body of the message to send
361     * @param sentIntent if not NULL this <code>PendingIntent</code> is
362     *  broadcast when the message is successfully sent, or failed.
363     *  The result code will be <code>Activity.RESULT_OK<code> for success,
364     *  or one of these errors:<br>
365     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
366     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
367     *  <code>RESULT_ERROR_NULL_PDU</code><br>
368     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
369     *  the extra "errorCode" containing a radio technology specific value,
370     *  generally only useful for troubleshooting.<br>
371     *  The per-application based SMS control checks sentIntent. If sentIntent
372     *  is NULL the caller will be checked against all unknown applications,
373     *  which cause smaller number of SMS to be sent in checking period.
374     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
375     *  broadcast when the message is delivered to the recipient.  The
376     *  raw pdu of the status report is in the extended data ("pdu").
377     */
378
379    private void sendDataInternal(String destAddr, String scAddr,
380            int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
381        if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
382            log("sendData: destAddr=" + destAddr + " scAddr=" + scAddr + " destPort=" +
383                destPort + " data='"+ HexDump.toHexString(data)  + "' sentIntent=" +
384                sentIntent + " deliveryIntent=" + deliveryIntent);
385        }
386        destAddr = filterDestAddress(destAddr);
387        mDispatchersController.sendData(destAddr, scAddr, destPort, data, sentIntent,
388                deliveryIntent);
389    }
390
391    /**
392     * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
393     * This method checks only if the calling package has the permission to send the sms.
394     */
395    public void sendText(String callingPackage, String destAddr, String scAddr,
396            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
397            boolean persistMessageForNonDefaultSmsApp) {
398        if (!checkCallingSendTextPermissions(
399                persistMessageForNonDefaultSmsApp, callingPackage, "Sending SMS message")) {
400            return;
401        }
402        sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
403            persistMessageForNonDefaultSmsApp, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
404            false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
405    }
406
407    /**
408     * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
409     * This method checks if the calling package or itself has the permission to send the sms.
410     */
411    public void sendTextWithSelfPermissions(String callingPackage, String destAddr, String scAddr,
412            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
413            boolean persistMessage) {
414        if (!checkCallingOrSelfSendSmsPermission(callingPackage, "Sending SMS message")) {
415            return;
416        }
417        sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
418            persistMessage, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, false /* expectMore */,
419            SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
420    }
421
422    /**
423     * Send a text based SMS.
424     *
425     * @param destAddr the address to send the message to
426     * @param scAddr is the service center address or null to use
427     *  the current default SMSC
428     * @param text the body of the message to send
429     * @param sentIntent if not NULL this <code>PendingIntent</code> is
430     *  broadcast when the message is successfully sent, or failed.
431     *  The result code will be <code>Activity.RESULT_OK<code> for success,
432     *  or one of these errors:<br>
433     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
434     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
435     *  <code>RESULT_ERROR_NULL_PDU</code><br>
436     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
437     *  the extra "errorCode" containing a radio technology specific value,
438     *  generally only useful for troubleshooting.<br>
439     *  The per-application based SMS control checks sentIntent. If sentIntent
440     *  is NULL the caller will be checked against all unknown applications,
441     *  which cause smaller number of SMS to be sent in checking period.
442     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
443     *  broadcast when the message is delivered to the recipient.  The
444     *  raw pdu of the status report is in the extended data ("pdu").
445     * @param persistMessageForNonDefaultSmsApp whether the sent message should
446     *  be automatically persisted in the SMS db. It only affects messages sent
447     *  by a non-default SMS app. Currently only the carrier app can set this
448     *  parameter to false to skip auto message persistence.
449     * @param priority Priority level of the message
450     *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
451     *  ---------------------------------
452     *  PRIORITY      | Level of Priority
453     *  ---------------------------------
454     *      '00'      |     Normal
455     *      '01'      |     Interactive
456     *      '10'      |     Urgent
457     *      '11'      |     Emergency
458     *  ----------------------------------
459     *  Any Other values including negative considered as Invalid Priority Indicator of the message.
460     * @param expectMore is a boolean to indicate the sending messages through same link or not.
461     * @param validityPeriod Validity Period of the message in mins.
462     *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
463     *  Validity Period(Minimum) -> 5 mins
464     *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
465     *  Any Other values including negative considered as Invalid Validity Period of the message.
466     */
467
468    private void sendTextInternal(String callingPackage, String destAddr, String scAddr,
469            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
470            boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore,
471            int validityPeriod) {
472        if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
473            log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +
474                " text='"+ text + "' sentIntent=" +
475                sentIntent + " deliveryIntent=" + deliveryIntent
476                + " priority=" + priority + " expectMore=" + expectMore
477                + " validityPeriod=" + validityPeriod);
478        }
479        destAddr = filterDestAddress(destAddr);
480        mDispatchersController.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
481                null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp,
482                priority, expectMore, validityPeriod);
483    }
484
485    /**
486     * Send a text based SMS with Messaging Options.
487     *
488     * @param destAddr the address to send the message to
489     * @param scAddr is the service center address or null to use
490     *  the current default SMSC
491     * @param text the body of the message to send
492     * @param sentIntent if not NULL this <code>PendingIntent</code> is
493     *  broadcast when the message is successfully sent, or failed.
494     *  The result code will be <code>Activity.RESULT_OK<code> for success,
495     *  or one of these errors:<br>
496     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
497     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
498     *  <code>RESULT_ERROR_NULL_PDU</code><br>
499     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
500     *  the extra "errorCode" containing a radio technology specific value,
501     *  generally only useful for troubleshooting.<br>
502     *  The per-application based SMS control checks sentIntent. If sentIntent
503     *  is NULL the caller will be checked against all unknown applications,
504     *  which cause smaller number of SMS to be sent in checking period.
505     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
506     *  broadcast when the message is delivered to the recipient.  The
507     *  raw pdu of the status report is in the extended data ("pdu").
508     * @param persistMessageForNonDefaultSmsApp whether the sent message should
509     *  be automatically persisted in the SMS db. It only affects messages sent
510     *  by a non-default SMS app. Currently only the carrier app can set this
511     *  parameter to false to skip auto message persistence.
512     * @param priority Priority level of the message
513     *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
514     *  ---------------------------------
515     *  PRIORITY      | Level of Priority
516     *  ---------------------------------
517     *      '00'      |     Normal
518     *      '01'      |     Interactive
519     *      '10'      |     Urgent
520     *      '11'      |     Emergency
521     *  ----------------------------------
522     *  Any Other values including negative considered as Invalid Priority Indicator of the message.
523     * @param expectMore is a boolean to indicate the sending messages through same link or not.
524     * @param validityPeriod Validity Period of the message in mins.
525     *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
526     *  Validity Period(Minimum) -> 5 mins
527     *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
528     *  Any Other values including negative considered as Invalid Validity Period of the message.
529     */
530
531    public void sendTextWithOptions(String callingPackage, String destAddr, String scAddr,
532            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
533            boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore,
534            int validityPeriod) {
535        if (!checkCallingOrSelfSendSmsPermission(callingPackage, "Sending SMS message")) {
536            return;
537        }
538        sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
539                persistMessageForNonDefaultSmsApp, priority, expectMore, validityPeriod);
540    }
541
542    /**
543     * Inject an SMS PDU into the android application framework.
544     *
545     * @param pdu is the byte array of pdu to be injected into android application framework
546     * @param format is the format of SMS pdu (3gpp or 3gpp2)
547     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
548     *  broadcast when the message is successfully received by the
549     *  android application framework. This intent is broadcasted at
550     *  the same time an SMS received from radio is acknowledged back.
551     */
552    public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
553        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
554                != PackageManager.PERMISSION_GRANTED) {
555            enforceCallerIsImsAppOrCarrierApp("injectSmsPdu");
556        }
557
558        if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
559            log("pdu: " + pdu +
560                "\n format=" + format +
561                "\n receivedIntent=" + receivedIntent);
562        }
563        mDispatchersController.injectSmsPdu(pdu, format,
564                result -> {
565                    if (receivedIntent != null) {
566                        try {
567                            receivedIntent.send(result);
568                        } catch (PendingIntent.CanceledException e) {
569                            Rlog.d(LOG_TAG, "receivedIntent cancelled.");
570                        }
571                    }
572                }
573        );
574    }
575
576    /**
577     * Send a multi-part text based SMS.
578     *
579     * @param destAddr the address to send the message to
580     * @param scAddr is the service center address or null to use
581     *   the current default SMSC
582     * @param parts an <code>ArrayList</code> of strings that, in order,
583     *   comprise the original message
584     * @param sentIntents if not null, an <code>ArrayList</code> of
585     *   <code>PendingIntent</code>s (one for each message part) that is
586     *   broadcast when the corresponding message part has been sent.
587     *   The result code will be <code>Activity.RESULT_OK<code> for success,
588     *   or one of these errors:
589     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
590     *   <code>RESULT_ERROR_RADIO_OFF</code>
591     *   <code>RESULT_ERROR_NULL_PDU</code>.
592     *  The per-application based SMS control checks sentIntent. If sentIntent
593     *  is NULL the caller will be checked against all unknown applications,
594     *  which cause smaller number of SMS to be sent in checking period.
595     * @param deliveryIntents if not null, an <code>ArrayList</code> of
596     *   <code>PendingIntent</code>s (one for each message part) that is
597     *   broadcast when the corresponding message part has been delivered
598     *   to the recipient.  The raw pdu of the status report is in the
599     *   extended data ("pdu").
600     */
601
602    public void sendMultipartText(String callingPackage, String destAddr, String scAddr,
603            List<String> parts, List<PendingIntent> sentIntents,
604            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp) {
605        sendMultipartTextWithOptions(callingPackage, destAddr, scAddr, parts, sentIntents,
606                deliveryIntents, persistMessageForNonDefaultSmsApp,
607                SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, false /* expectMore */,
608                SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
609    }
610
611    /**
612     * Send a multi-part text based SMS with Messaging Options.
613     *
614     * @param destAddr the address to send the message to
615     * @param scAddr is the service center address or null to use
616     *   the current default SMSC
617     * @param parts an <code>ArrayList</code> of strings that, in order,
618     *   comprise the original message
619     * @param sentIntents if not null, an <code>ArrayList</code> of
620     *   <code>PendingIntent</code>s (one for each message part) that is
621     *   broadcast when the corresponding message part has been sent.
622     *   The result code will be <code>Activity.RESULT_OK<code> for success,
623     *   or one of these errors:
624     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
625     *   <code>RESULT_ERROR_RADIO_OFF</code>
626     *   <code>RESULT_ERROR_NULL_PDU</code>.
627     *  The per-application based SMS control checks sentIntent. If sentIntent
628     *  is NULL the caller will be checked against all unknown applications,
629     *  which cause smaller number of SMS to be sent in checking period.
630     * @param deliveryIntents if not null, an <code>ArrayList</code> of
631     *   <code>PendingIntent</code>s (one for each message part) that is
632     *   broadcast when the corresponding message part has been delivered
633     *   to the recipient.  The raw pdu of the status report is in the
634     *   extended data ("pdu").
635     * @param persistMessageForNonDefaultSmsApp whether the sent message should
636     *   be automatically persisted in the SMS db. It only affects messages sent
637     *   by a non-default SMS app. Currently only the carrier app can set this
638     *   parameter to false to skip auto message persistence.
639     * @param priority Priority level of the message
640     *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
641     *  ---------------------------------
642     *  PRIORITY      | Level of Priority
643     *  ---------------------------------
644     *      '00'      |     Normal
645     *      '01'      |     Interactive
646     *      '10'      |     Urgent
647     *      '11'      |     Emergency
648     *  ----------------------------------
649     *  Any Other values including negative considered as Invalid Priority Indicator of the message.
650     * @param expectMore is a boolean to indicate the sending messages through same link or not.
651     * @param validityPeriod Validity Period of the message in mins.
652     *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
653     *  Validity Period(Minimum) -> 5 mins
654     *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
655     *  Any Other values including negative considered as Invalid Validity Period of the message.
656     */
657
658    public void sendMultipartTextWithOptions(String callingPackage, String destAddr,
659            String scAddr, List<String> parts, List<PendingIntent> sentIntents,
660            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp,
661            int priority, boolean expectMore, int validityPeriod) {
662        if (!checkCallingSendTextPermissions(
663                persistMessageForNonDefaultSmsApp, callingPackage, "Sending SMS message")) {
664            return;
665        }
666        if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
667            int i = 0;
668            for (String part : parts) {
669                log("sendMultipartTextWithOptions: destAddr=" + destAddr + ", srAddr=" + scAddr +
670                        ", part[" + (i++) + "]=" + part);
671            }
672        }
673
674        destAddr = filterDestAddress(destAddr);
675
676        if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
677            for (int i = 0; i < parts.size(); i++) {
678                // If EMS is not supported, we have to break down EMS into single segment SMS
679                // and add page info " x/y".
680                String singlePart = parts.get(i);
681                if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
682                    singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
683                } else {
684                    singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size());
685                }
686
687                PendingIntent singleSentIntent = null;
688                if (sentIntents != null && sentIntents.size() > i) {
689                    singleSentIntent = sentIntents.get(i);
690                }
691
692                PendingIntent singleDeliveryIntent = null;
693                if (deliveryIntents != null && deliveryIntents.size() > i) {
694                    singleDeliveryIntent = deliveryIntents.get(i);
695                }
696
697                mDispatchersController.sendText(destAddr, scAddr, singlePart,
698                        singleSentIntent, singleDeliveryIntent,
699                        null/*messageUri*/, callingPackage,
700                        persistMessageForNonDefaultSmsApp,
701                        priority, expectMore, validityPeriod);
702            }
703            return;
704        }
705
706        mDispatchersController.sendMultipartText(destAddr,
707                                      scAddr,
708                                      (ArrayList<String>) parts,
709                                      (ArrayList<PendingIntent>) sentIntents,
710                                      (ArrayList<PendingIntent>) deliveryIntents,
711                                      null, callingPackage, persistMessageForNonDefaultSmsApp,
712                                      priority, expectMore, validityPeriod);
713    }
714
715    public int getPremiumSmsPermission(String packageName) {
716        return mDispatchersController.getPremiumSmsPermission(packageName);
717    }
718
719
720    public void setPremiumSmsPermission(String packageName, int permission) {
721        mDispatchersController.setPremiumSmsPermission(packageName, permission);
722    }
723
724    /**
725     * create SmsRawData lists from all sms record byte[]
726     * Use null to indicate "free" record
727     *
728     * @param messages List of message records from EF_SMS.
729     * @return SmsRawData list of all in-used records
730     */
731    protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) {
732        int count = messages.size();
733        ArrayList<SmsRawData> ret;
734
735        ret = new ArrayList<SmsRawData>(count);
736
737        for (int i = 0; i < count; i++) {
738            byte[] ba = messages.get(i);
739            if (ba[0] == STATUS_ON_ICC_FREE) {
740                ret.add(null);
741            } else {
742                ret.add(new SmsRawData(messages.get(i)));
743            }
744        }
745
746        return ret;
747    }
748
749    /**
750     * Generates an EF_SMS record from status and raw PDU.
751     *
752     * @param status Message status.  See TS 51.011 10.5.3.
753     * @param pdu Raw message PDU.
754     * @return byte array for the record.
755     */
756    protected byte[] makeSmsRecordData(int status, byte[] pdu) {
757        byte[] data;
758        if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
759            data = new byte[SmsManager.SMS_RECORD_LENGTH];
760        } else {
761            data = new byte[SmsManager.CDMA_SMS_RECORD_LENGTH];
762        }
763
764        // Status bits for this record.  See TS 51.011 10.5.3
765        data[0] = (byte)(status & 7);
766
767        System.arraycopy(pdu, 0, data, 1, pdu.length);
768
769        // Pad out with 0xFF's.
770        for (int j = pdu.length+1; j < data.length; j++) {
771            data[j] = -1;
772        }
773
774        return data;
775    }
776
777    public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
778        return enableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType);
779    }
780
781    public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
782        return disableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType);
783    }
784
785    public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
786        if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM) {
787            return enableGsmBroadcastRange(startMessageId, endMessageId);
788        } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA) {
789            return enableCdmaBroadcastRange(startMessageId, endMessageId);
790        } else {
791            throw new IllegalArgumentException("Not a supportted RAN Type");
792        }
793    }
794
795    public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
796        if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM ) {
797            return disableGsmBroadcastRange(startMessageId, endMessageId);
798        } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA)  {
799            return disableCdmaBroadcastRange(startMessageId, endMessageId);
800        } else {
801            throw new IllegalArgumentException("Not a supportted RAN Type");
802        }
803    }
804
805    synchronized public boolean enableGsmBroadcastRange(int startMessageId, int endMessageId) {
806
807        mContext.enforceCallingPermission(
808                "android.permission.RECEIVE_SMS",
809                "Enabling cell broadcast SMS");
810
811        String client = mContext.getPackageManager().getNameForUid(
812                Binder.getCallingUid());
813
814        if (!mCellBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
815            log("Failed to add GSM cell broadcast subscription for MID range " + startMessageId
816                    + " to " + endMessageId + " from client " + client);
817            return false;
818        }
819
820        if (DBG)
821            log("Added GSM cell broadcast subscription for MID range " + startMessageId
822                    + " to " + endMessageId + " from client " + client);
823
824        setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
825
826        return true;
827    }
828
829    synchronized public boolean disableGsmBroadcastRange(int startMessageId, int endMessageId) {
830
831        mContext.enforceCallingPermission(
832                "android.permission.RECEIVE_SMS",
833                "Disabling cell broadcast SMS");
834
835        String client = mContext.getPackageManager().getNameForUid(
836                Binder.getCallingUid());
837
838        if (!mCellBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
839            log("Failed to remove GSM cell broadcast subscription for MID range " + startMessageId
840                    + " to " + endMessageId + " from client " + client);
841            return false;
842        }
843
844        if (DBG)
845            log("Removed GSM cell broadcast subscription for MID range " + startMessageId
846                    + " to " + endMessageId + " from client " + client);
847
848        setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
849
850        return true;
851    }
852
853    synchronized public boolean enableCdmaBroadcastRange(int startMessageId, int endMessageId) {
854
855        mContext.enforceCallingPermission(
856                "android.permission.RECEIVE_SMS",
857                "Enabling cdma broadcast SMS");
858
859        String client = mContext.getPackageManager().getNameForUid(
860                Binder.getCallingUid());
861
862        if (!mCdmaBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
863            log("Failed to add cdma broadcast subscription for MID range " + startMessageId
864                    + " to " + endMessageId + " from client " + client);
865            return false;
866        }
867
868        if (DBG)
869            log("Added cdma broadcast subscription for MID range " + startMessageId
870                    + " to " + endMessageId + " from client " + client);
871
872        setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty());
873
874        return true;
875    }
876
877    synchronized public boolean disableCdmaBroadcastRange(int startMessageId, int endMessageId) {
878
879        mContext.enforceCallingPermission(
880                "android.permission.RECEIVE_SMS",
881                "Disabling cell broadcast SMS");
882
883        String client = mContext.getPackageManager().getNameForUid(
884                Binder.getCallingUid());
885
886        if (!mCdmaBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
887            log("Failed to remove cdma broadcast subscription for MID range " + startMessageId
888                    + " to " + endMessageId + " from client " + client);
889            return false;
890        }
891
892        if (DBG)
893            log("Removed cdma broadcast subscription for MID range " + startMessageId
894                    + " to " + endMessageId + " from client " + client);
895
896        setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty());
897
898        return true;
899    }
900
901    class CellBroadcastRangeManager extends IntRangeManager {
902        private ArrayList<SmsBroadcastConfigInfo> mConfigList =
903                new ArrayList<SmsBroadcastConfigInfo>();
904
905        /**
906         * Called when the list of enabled ranges has changed. This will be
907         * followed by zero or more calls to {@link #addRange} followed by
908         * a call to {@link #finishUpdate}.
909         */
910        protected void startUpdate() {
911            mConfigList.clear();
912        }
913
914        /**
915         * Called after {@link #startUpdate} to indicate a range of enabled
916         * values.
917         * @param startId the first id included in the range
918         * @param endId the last id included in the range
919         */
920        protected void addRange(int startId, int endId, boolean selected) {
921            mConfigList.add(new SmsBroadcastConfigInfo(startId, endId,
922                        SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected));
923        }
924
925        /**
926         * Called to indicate the end of a range update started by the
927         * previous call to {@link #startUpdate}.
928         * @return true if successful, false otherwise
929         */
930        protected boolean finishUpdate() {
931            if (mConfigList.isEmpty()) {
932                return true;
933            } else {
934                SmsBroadcastConfigInfo[] configs =
935                        mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]);
936                return setCellBroadcastConfig(configs);
937            }
938        }
939    }
940
941    class CdmaBroadcastRangeManager extends IntRangeManager {
942        private ArrayList<CdmaSmsBroadcastConfigInfo> mConfigList =
943                new ArrayList<CdmaSmsBroadcastConfigInfo>();
944
945        /**
946         * Called when the list of enabled ranges has changed. This will be
947         * followed by zero or more calls to {@link #addRange} followed by a
948         * call to {@link #finishUpdate}.
949         */
950        protected void startUpdate() {
951            mConfigList.clear();
952        }
953
954        /**
955         * Called after {@link #startUpdate} to indicate a range of enabled
956         * values.
957         * @param startId the first id included in the range
958         * @param endId the last id included in the range
959         */
960        protected void addRange(int startId, int endId, boolean selected) {
961            mConfigList.add(new CdmaSmsBroadcastConfigInfo(startId, endId,
962                    1, selected));
963        }
964
965        /**
966         * Called to indicate the end of a range update started by the previous
967         * call to {@link #startUpdate}.
968         * @return true if successful, false otherwise
969         */
970        protected boolean finishUpdate() {
971            if (mConfigList.isEmpty()) {
972                return true;
973            } else {
974                CdmaSmsBroadcastConfigInfo[] configs =
975                        mConfigList.toArray(new CdmaSmsBroadcastConfigInfo[mConfigList.size()]);
976                return setCdmaBroadcastConfig(configs);
977            }
978        }
979    }
980
981    private boolean setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs) {
982        if (DBG)
983            log("Calling setGsmBroadcastConfig with " + configs.length + " configurations");
984
985        synchronized (mLock) {
986            Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE);
987
988            mSuccess = false;
989            mPhone.mCi.setGsmBroadcastConfig(configs, response);
990
991            try {
992                mLock.wait();
993            } catch (InterruptedException e) {
994                log("interrupted while trying to set cell broadcast config");
995            }
996        }
997
998        return mSuccess;
999    }
1000
1001    private boolean setCellBroadcastActivation(boolean activate) {
1002        if (DBG)
1003            log("Calling setCellBroadcastActivation(" + activate + ')');
1004
1005        synchronized (mLock) {
1006            Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
1007
1008            mSuccess = false;
1009            mPhone.mCi.setGsmBroadcastActivation(activate, response);
1010
1011            try {
1012                mLock.wait();
1013            } catch (InterruptedException e) {
1014                log("interrupted while trying to set cell broadcast activation");
1015            }
1016        }
1017
1018        return mSuccess;
1019    }
1020
1021    private boolean setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs) {
1022        if (DBG)
1023            log("Calling setCdmaBroadcastConfig with " + configs.length + " configurations");
1024
1025        synchronized (mLock) {
1026            Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE);
1027
1028            mSuccess = false;
1029            mPhone.mCi.setCdmaBroadcastConfig(configs, response);
1030
1031            try {
1032                mLock.wait();
1033            } catch (InterruptedException e) {
1034                log("interrupted while trying to set cdma broadcast config");
1035            }
1036        }
1037
1038        return mSuccess;
1039    }
1040
1041    private boolean setCdmaBroadcastActivation(boolean activate) {
1042        if (DBG)
1043            log("Calling setCdmaBroadcastActivation(" + activate + ")");
1044
1045        synchronized (mLock) {
1046            Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
1047
1048            mSuccess = false;
1049            mPhone.mCi.setCdmaBroadcastActivation(activate, response);
1050
1051            try {
1052                mLock.wait();
1053            } catch (InterruptedException e) {
1054                log("interrupted while trying to set cdma broadcast activation");
1055            }
1056        }
1057
1058        return mSuccess;
1059    }
1060
1061    protected void log(String msg) {
1062        Log.d(LOG_TAG, "[IccSmsInterfaceManager] " + msg);
1063    }
1064
1065    public boolean isImsSmsSupported() {
1066        return mDispatchersController.isIms();
1067    }
1068
1069    public String getImsSmsFormat() {
1070        return mDispatchersController.getImsSmsFormat();
1071    }
1072
1073    public void sendStoredText(String callingPkg, Uri messageUri, String scAddress,
1074            PendingIntent sentIntent, PendingIntent deliveryIntent) {
1075        if (!checkCallingSendSmsPermission(callingPkg, "Sending SMS message")) {
1076            return;
1077        }
1078        if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
1079            log("sendStoredText: scAddr=" + scAddress + " messageUri=" + messageUri
1080                    + " sentIntent=" + sentIntent + " deliveryIntent=" + deliveryIntent);
1081        }
1082        final ContentResolver resolver = mContext.getContentResolver();
1083        if (!isFailedOrDraft(resolver, messageUri)) {
1084            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredText: not FAILED or DRAFT message");
1085            returnUnspecifiedFailure(sentIntent);
1086            return;
1087        }
1088        final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
1089        if (textAndAddress == null) {
1090            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredText: can not load text");
1091            returnUnspecifiedFailure(sentIntent);
1092            return;
1093        }
1094        textAndAddress[1] = filterDestAddress(textAndAddress[1]);
1095        mDispatchersController.sendText(textAndAddress[1], scAddress, textAndAddress[0],
1096                sentIntent, deliveryIntent, messageUri, callingPkg,
1097                true /* persistMessageForNonDefaultSmsApp */, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
1098                false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
1099    }
1100
1101    public void sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress,
1102            List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
1103        if (!checkCallingSendSmsPermission(callingPkg, "Sending SMS message")) {
1104            return;
1105        }
1106        final ContentResolver resolver = mContext.getContentResolver();
1107        if (!isFailedOrDraft(resolver, messageUri)) {
1108            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: "
1109                    + "not FAILED or DRAFT message");
1110            returnUnspecifiedFailure(sentIntents);
1111            return;
1112        }
1113        final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
1114        if (textAndAddress == null) {
1115            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: can not load text");
1116            returnUnspecifiedFailure(sentIntents);
1117            return;
1118        }
1119        final ArrayList<String> parts = SmsManager.getDefault().divideMessage(textAndAddress[0]);
1120        if (parts == null || parts.size() < 1) {
1121            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: can not divide text");
1122            returnUnspecifiedFailure(sentIntents);
1123            return;
1124        }
1125
1126        textAndAddress[1] = filterDestAddress(textAndAddress[1]);
1127
1128        if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
1129            for (int i = 0; i < parts.size(); i++) {
1130                // If EMS is not supported, we have to break down EMS into single segment SMS
1131                // and add page info " x/y".
1132                String singlePart = parts.get(i);
1133                if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
1134                    singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
1135                } else {
1136                    singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size());
1137                }
1138
1139                PendingIntent singleSentIntent = null;
1140                if (sentIntents != null && sentIntents.size() > i) {
1141                    singleSentIntent = sentIntents.get(i);
1142                }
1143
1144                PendingIntent singleDeliveryIntent = null;
1145                if (deliveryIntents != null && deliveryIntents.size() > i) {
1146                    singleDeliveryIntent = deliveryIntents.get(i);
1147                }
1148
1149                mDispatchersController.sendText(textAndAddress[1], scAddress, singlePart,
1150                        singleSentIntent, singleDeliveryIntent, messageUri, callingPkg,
1151                        true  /* persistMessageForNonDefaultSmsApp */,
1152                        SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
1153                        false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
1154            }
1155            return;
1156        }
1157
1158        mDispatchersController.sendMultipartText(
1159                textAndAddress[1], // destAddress
1160                scAddress,
1161                parts,
1162                (ArrayList<PendingIntent>) sentIntents,
1163                (ArrayList<PendingIntent>) deliveryIntents,
1164                messageUri,
1165                callingPkg,
1166                true  /* persistMessageForNonDefaultSmsApp */,
1167                SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
1168                false /* expectMore */,
1169                SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
1170    }
1171
1172    private boolean isFailedOrDraft(ContentResolver resolver, Uri messageUri) {
1173        // Clear the calling identity and query the database using the phone user id
1174        // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
1175        // between the calling uid and the package uid
1176        final long identity = Binder.clearCallingIdentity();
1177        Cursor cursor = null;
1178        try {
1179            cursor = resolver.query(
1180                    messageUri,
1181                    new String[]{ Telephony.Sms.TYPE },
1182                    null/*selection*/,
1183                    null/*selectionArgs*/,
1184                    null/*sortOrder*/);
1185            if (cursor != null && cursor.moveToFirst()) {
1186                final int type = cursor.getInt(0);
1187                return type == Telephony.Sms.MESSAGE_TYPE_DRAFT
1188                        || type == Telephony.Sms.MESSAGE_TYPE_FAILED;
1189            }
1190        } catch (SQLiteException e) {
1191            Log.e(LOG_TAG, "[IccSmsInterfaceManager]isFailedOrDraft: query message type failed", e);
1192        } finally {
1193            if (cursor != null) {
1194                cursor.close();
1195            }
1196            Binder.restoreCallingIdentity(identity);
1197        }
1198        return false;
1199    }
1200
1201    // Return an array including both the SMS text (0) and address (1)
1202    private String[] loadTextAndAddress(ContentResolver resolver, Uri messageUri) {
1203        // Clear the calling identity and query the database using the phone user id
1204        // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
1205        // between the calling uid and the package uid
1206        final long identity = Binder.clearCallingIdentity();
1207        Cursor cursor = null;
1208        try {
1209            cursor = resolver.query(
1210                    messageUri,
1211                    new String[]{
1212                            Telephony.Sms.BODY,
1213                            Telephony.Sms.ADDRESS
1214                    },
1215                    null/*selection*/,
1216                    null/*selectionArgs*/,
1217                    null/*sortOrder*/);
1218            if (cursor != null && cursor.moveToFirst()) {
1219                return new String[]{ cursor.getString(0), cursor.getString(1) };
1220            }
1221        } catch (SQLiteException e) {
1222            Log.e(LOG_TAG, "[IccSmsInterfaceManager]loadText: query message text failed", e);
1223        } finally {
1224            if (cursor != null) {
1225                cursor.close();
1226            }
1227            Binder.restoreCallingIdentity(identity);
1228        }
1229        return null;
1230    }
1231
1232    private void returnUnspecifiedFailure(PendingIntent pi) {
1233        if (pi != null) {
1234            try {
1235                pi.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
1236            } catch (PendingIntent.CanceledException e) {
1237                // ignore
1238            }
1239        }
1240    }
1241
1242    private void returnUnspecifiedFailure(List<PendingIntent> pis) {
1243        if (pis == null) {
1244            return;
1245        }
1246        for (PendingIntent pi : pis) {
1247            returnUnspecifiedFailure(pi);
1248        }
1249    }
1250
1251    /**
1252     * Check that the caller can send text messages.
1253     *
1254     * For persisted messages, the caller just needs the SEND_SMS permission. For unpersisted
1255     * messages, the caller must either be the IMS app or a carrier-privileged app, or they must
1256     * have both the MODIFY_PHONE_STATE and SEND_SMS permissions.
1257     *
1258     * @throws SecurityException if the caller is missing all necessary permission declaration or
1259     *                           has had a necessary runtime permission revoked.
1260     * @return true unless the caller has all necessary permissions but has a revoked AppOps bit.
1261     */
1262    @VisibleForTesting
1263    public boolean checkCallingSendTextPermissions(
1264            boolean persistMessageForNonDefaultSmsApp, String callingPackage, String message) {
1265        // TODO(b/75978989): Should we allow IMS/carrier apps for persisted messages as well?
1266        if (!persistMessageForNonDefaultSmsApp) {
1267            try {
1268                enforceCallerIsImsAppOrCarrierApp(message);
1269                // No need to also check SEND_SMS.
1270                return true;
1271            } catch (SecurityException e) {
1272                mContext.enforceCallingPermission(
1273                        android.Manifest.permission.MODIFY_PHONE_STATE, message);
1274            }
1275        }
1276        return checkCallingSendSmsPermission(callingPackage, message);
1277    }
1278
1279    /**
1280     * Check that the caller (or self, if this is not an IPC) has SEND_SMS permissions.
1281     *
1282     * @throws SecurityException if the caller is missing the permission declaration or has had the
1283     *                           permission revoked at runtime.
1284     * @return whether the caller has the OP_SEND_SMS AppOps bit.
1285     */
1286    private boolean checkCallingOrSelfSendSmsPermission(String callingPackage, String message) {
1287        mContext.enforceCallingOrSelfPermission(Manifest.permission.SEND_SMS, message);
1288        return mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage)
1289                == AppOpsManager.MODE_ALLOWED;
1290    }
1291
1292    /**
1293     * Check that the caller has SEND_SMS permissions. Can only be called during an IPC.
1294     *
1295     * @throws SecurityException if the caller is missing the permission declaration or has had the
1296     *                           permission revoked at runtime.
1297     * @return whether the caller has the OP_SEND_SMS AppOps bit.
1298     */
1299    private boolean checkCallingSendSmsPermission(String callingPackage, String message) {
1300        mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, message);
1301        return mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage)
1302                == AppOpsManager.MODE_ALLOWED;
1303    }
1304
1305    /**
1306     * Enforces that the caller is one of the following apps:
1307     * <ul>
1308     *     <li> IMS App
1309     *     <li> Carrier App
1310     * </ul>
1311     */
1312    @VisibleForTesting
1313    public void enforceCallerIsImsAppOrCarrierApp(String message) {
1314        int callingUid = Binder.getCallingUid();
1315        String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
1316                new Intent(CarrierMessagingService.SERVICE_INTERFACE));
1317        try {
1318            if (carrierImsPackage != null
1319                    && callingUid == mContext.getPackageManager().getPackageUid(
1320                            carrierImsPackage, 0)) {
1321              return;
1322            }
1323        } catch (PackageManager.NameNotFoundException e) {
1324            if (Rlog.isLoggable("SMS", Log.DEBUG)) {
1325                log("Cannot find configured carrier ims package");
1326            }
1327        }
1328
1329        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mPhone.getSubId(), message);
1330    }
1331
1332    private String filterDestAddress(String destAddr) {
1333        String result  = null;
1334        result = SmsNumberUtils.filterDestAddr(mPhone, destAddr);
1335        return result != null ? result : destAddr;
1336    }
1337
1338}
1339