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