SmsManager.java revision b29851580bba4a13ddbf7a534d8b09295eb2c60f
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 android.telephony; 18 19import android.app.ActivityThread; 20import android.app.PendingIntent; 21import android.content.ContentValues; 22import android.net.Uri; 23import android.os.RemoteException; 24import android.os.ServiceManager; 25import android.text.TextUtils; 26import android.util.Log; 27 28import com.android.internal.telephony.ISms; 29import com.android.internal.telephony.SmsRawData; 30import com.android.internal.telephony.IMms; 31import com.android.internal.telephony.uicc.IccConstants; 32 33import java.util.ArrayList; 34import java.util.Arrays; 35import java.util.List; 36 37/* 38 * TODO(code review): Curious question... Why are a lot of these 39 * methods not declared as static, since they do not seem to require 40 * any local object state? Presumably this cannot be changed without 41 * interfering with the API... 42 */ 43 44/** 45 * Manages SMS operations such as sending data, text, and pdu SMS messages. 46 * Get this object by calling the static method {@link #getDefault()}. 47 * 48 * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19) 49 * and higher, see {@link android.provider.Telephony}. 50 */ 51public final class SmsManager { 52 /** Singleton object constructed during class initialization. */ 53 private static final SmsManager sInstance = new SmsManager(); 54 private static final int DEFAULT_SUB = 0; 55 56 /** 57 * Send a text based SMS. 58 * 59 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 60 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 61 * 62 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 63 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 64 * writes messages sent using this method to the SMS Provider (the default SMS app is always 65 * responsible for writing its sent messages to the SMS Provider). For information about 66 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 67 * 68 * 69 * @param destinationAddress the address to send the message to 70 * @param scAddress is the service center address or null to use 71 * the current default SMSC 72 * @param text the body of the message to send 73 * @param sentIntent if not NULL this <code>PendingIntent</code> is 74 * broadcast when the message is successfully sent, or failed. 75 * The result code will be <code>Activity.RESULT_OK</code> for success, 76 * or one of these errors:<br> 77 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 78 * <code>RESULT_ERROR_RADIO_OFF</code><br> 79 * <code>RESULT_ERROR_NULL_PDU</code><br> 80 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 81 * the extra "errorCode" containing a radio technology specific value, 82 * generally only useful for troubleshooting.<br> 83 * The per-application based SMS control checks sentIntent. If sentIntent 84 * is NULL the caller will be checked against all unknown applications, 85 * which cause smaller number of SMS to be sent in checking period. 86 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 87 * broadcast when the message is delivered to the recipient. The 88 * raw pdu of the status report is in the extended data ("pdu"). 89 * 90 * @throws IllegalArgumentException if destinationAddress or text are empty 91 */ 92 public void sendTextMessage( 93 String destinationAddress, String scAddress, String text, 94 PendingIntent sentIntent, PendingIntent deliveryIntent) { 95 sendTextMessage(getPreferredSmsSubscription(), destinationAddress, scAddress, text, 96 sentIntent, deliveryIntent); 97 } 98 99 /** 100 * Send a text based SMS. 101 * 102 * @param destinationAddress the address to send the message to 103 * @param scAddress is the service center address or null to use 104 * the current default SMSC 105 * @param text the body of the message to send 106 * @param sentIntent if not NULL this <code>PendingIntent</code> is 107 * broadcast when the message is successfully sent, or failed. 108 * The result code will be <code>Activity.RESULT_OK</code> for success, 109 * or one of these errors:<br> 110 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 111 * <code>RESULT_ERROR_RADIO_OFF</code><br> 112 * <code>RESULT_ERROR_NULL_PDU</code><br> 113 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 114 * the extra "errorCode" containing a radio technology specific value, 115 * generally only useful for troubleshooting.<br> 116 * The per-application based SMS control checks sentIntent. If sentIntent 117 * is NULL the caller will be checked against all unknown applications, 118 * which cause smaller number of SMS to be sent in checking period. 119 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 120 * broadcast when the message is delivered to the recipient. The 121 * raw pdu of the status report is in the extended data ("pdu"). 122 * @param subId on which the SMS has to be sent. 123 * 124 * @throws IllegalArgumentException if destinationAddress or text are empty 125 * 126 */ 127 /** @hide */ 128 public void sendTextMessage( 129 long subId, String destinationAddress, String scAddress, String text, 130 PendingIntent sentIntent, PendingIntent deliveryIntent) { 131 if (TextUtils.isEmpty(destinationAddress)) { 132 throw new IllegalArgumentException("Invalid destinationAddress"); 133 } 134 135 if (TextUtils.isEmpty(text)) { 136 throw new IllegalArgumentException("Invalid message body"); 137 } 138 139 try { 140 ISms iccISms = getISmsServiceOrThrow(); 141 iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress, 142 scAddress, text, sentIntent, deliveryIntent); 143 } catch (RemoteException ex) { 144 // ignore it 145 } 146 } 147 148 /** 149 * TODO Move this to new CarrierSmsManager class. 150 * 151 * Inject an SMS PDU into the android application framework. 152 * 153 * @param pdu is the byte array of pdu to be injected into android application framework 154 * @param format is the format of SMS pdu (3gpp or 3gpp2) 155 * @param receivedIntent if not NULL this <code>PendingIntent</code> is 156 * broadcast when the message is successfully received by the 157 * android application framework. This intent is broadcasted at 158 * the same time an SMS received from radio is acknowledged back. 159 * 160 * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2. 161 * {@hide} 162 */ 163 public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) { 164 if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) { 165 // Format must be either 3gpp or 3gpp2. 166 throw new IllegalArgumentException( 167 "Invalid pdu format. format must be either 3gpp or 3gpp2"); 168 } 169 try { 170 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 171 if (iccISms != null) { 172 iccISms.injectSmsPdu(pdu, format, receivedIntent); 173 } 174 } catch (RemoteException ex) { 175 // ignore it 176 } 177 } 178 179 /** 180 * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary. 181 * This outbound message was handled by the carrier app. If the carrier app fails to send 182 * this message, it would be resent by PSTN. 183 * 184 * @param messageRef the reference number of the SMS message. 185 * @param success True if and only if the message was sent successfully. If its value is 186 * false, this message should be resent via PSTN. 187 * {@hide} 188 */ 189 public void updateSmsSendStatus(int messageRef, boolean success) { 190 try { 191 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 192 if (iccISms != null) { 193 iccISms.updateSmsSendStatus(messageRef, success); 194 } 195 } catch (RemoteException ex) { 196 // ignore it 197 } 198 } 199 200 /** 201 * Divide a message text into several fragments, none bigger than 202 * the maximum SMS message size. 203 * 204 * @param text the original message. Must not be null. 205 * @return an <code>ArrayList</code> of strings that, in order, 206 * comprise the original message 207 * 208 * @throws IllegalArgumentException if text is null 209 */ 210 public ArrayList<String> divideMessage(String text) { 211 if (null == text) { 212 throw new IllegalArgumentException("text is null"); 213 } 214 return SmsMessage.fragmentText(text); 215 } 216 217 /** 218 * Send a multi-part text based SMS. The callee should have already 219 * divided the message into correctly sized parts by calling 220 * <code>divideMessage</code>. 221 * 222 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 223 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 224 * 225 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 226 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 227 * writes messages sent using this method to the SMS Provider (the default SMS app is always 228 * responsible for writing its sent messages to the SMS Provider). For information about 229 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 230 * 231 * @param destinationAddress the address to send the message to 232 * @param scAddress is the service center address or null to use 233 * the current default SMSC 234 * @param parts an <code>ArrayList</code> of strings that, in order, 235 * comprise the original message 236 * @param sentIntents if not null, an <code>ArrayList</code> of 237 * <code>PendingIntent</code>s (one for each message part) that is 238 * broadcast when the corresponding message part has been sent. 239 * The result code will be <code>Activity.RESULT_OK</code> for success, 240 * or one of these errors:<br> 241 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 242 * <code>RESULT_ERROR_RADIO_OFF</code><br> 243 * <code>RESULT_ERROR_NULL_PDU</code><br> 244 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 245 * the extra "errorCode" containing a radio technology specific value, 246 * generally only useful for troubleshooting.<br> 247 * The per-application based SMS control checks sentIntent. If sentIntent 248 * is NULL the caller will be checked against all unknown applications, 249 * which cause smaller number of SMS to be sent in checking period. 250 * @param deliveryIntents if not null, an <code>ArrayList</code> of 251 * <code>PendingIntent</code>s (one for each message part) that is 252 * broadcast when the corresponding message part has been delivered 253 * to the recipient. The raw pdu of the status report is in the 254 * extended data ("pdu"). 255 * 256 * @throws IllegalArgumentException if destinationAddress or data are empty 257 */ 258 public void sendMultipartTextMessage( 259 String destinationAddress, String scAddress, ArrayList<String> parts, 260 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 261 sendMultipartTextMessage(getPreferredSmsSubscription(), destinationAddress, scAddress, parts, sentIntents, 262 deliveryIntents); 263 } 264 265 /** 266 * Send a multi-part text based SMS. The callee should have already 267 * divided the message into correctly sized parts by calling 268 * <code>divideMessage</code>. 269 * 270 * @param destinationAddress the address to send the message to 271 * @param scAddress is the service center address or null to use 272 * the current default SMSC 273 * @param parts an <code>ArrayList</code> of strings that, in order, 274 * comprise the original message 275 * @param sentIntents if not null, an <code>ArrayList</code> of 276 * <code>PendingIntent</code>s (one for each message part) that is 277 * broadcast when the corresponding message part has been sent. 278 * The result code will be <code>Activity.RESULT_OK</code> for success, 279 * or one of these errors:<br> 280 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 281 * <code>RESULT_ERROR_RADIO_OFF</code><br> 282 * <code>RESULT_ERROR_NULL_PDU</code><br> 283 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 284 * the extra "errorCode" containing a radio technology specific value, 285 * generally only useful for troubleshooting.<br> 286 * The per-application based SMS control checks sentIntent. If sentIntent 287 * is NULL the caller will be checked against all unknown applications, 288 * which cause smaller number of SMS to be sent in checking period. 289 * @param deliveryIntents if not null, an <code>ArrayList</code> of 290 * <code>PendingIntent</code>s (one for each message part) that is 291 * broadcast when the corresponding message part has been delivered 292 * to the recipient. The raw pdu of the status report is in the 293 * extended data ("pdu"). 294 * @param subId on which the SMS has to be sent. 295 * 296 * @throws IllegalArgumentException if destinationAddress or data are empty 297 */ 298 /** @hide */ 299 public void sendMultipartTextMessage(long subId, String destinationAddress, String scAddress, 300 ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, 301 ArrayList<PendingIntent> deliveryIntents) { 302 if (TextUtils.isEmpty(destinationAddress)) { 303 throw new IllegalArgumentException("Invalid destinationAddress"); 304 } 305 if (parts == null || parts.size() < 1) { 306 throw new IllegalArgumentException("Invalid message body"); 307 } 308 309 if (parts.size() > 1) { 310 try { 311 ISms iccISms = getISmsServiceOrThrow(); 312 iccISms.sendMultipartText(ActivityThread.currentPackageName(), 313 destinationAddress, scAddress, parts, 314 sentIntents, deliveryIntents); 315 } catch (RemoteException ex) { 316 // ignore it 317 } 318 } else { 319 PendingIntent sentIntent = null; 320 PendingIntent deliveryIntent = null; 321 if (sentIntents != null && sentIntents.size() > 0) { 322 sentIntent = sentIntents.get(0); 323 } 324 if (deliveryIntents != null && deliveryIntents.size() > 0) { 325 deliveryIntent = deliveryIntents.get(0); 326 } 327 sendTextMessage(destinationAddress, scAddress, parts.get(0), 328 sentIntent, deliveryIntent); 329 } 330 } 331 332 /** 333 * Send a data based SMS to a specific application port. 334 * 335 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 336 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 337 * 338 * @param destinationAddress the address to send the message to 339 * @param scAddress is the service center address or null to use 340 * the current default SMSC 341 * @param destinationPort the port to deliver the message to 342 * @param data the body of the message to send 343 * @param sentIntent if not NULL this <code>PendingIntent</code> is 344 * broadcast when the message is successfully sent, or failed. 345 * The result code will be <code>Activity.RESULT_OK</code> for success, 346 * or one of these errors:<br> 347 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 348 * <code>RESULT_ERROR_RADIO_OFF</code><br> 349 * <code>RESULT_ERROR_NULL_PDU</code><br> 350 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 351 * the extra "errorCode" containing a radio technology specific value, 352 * generally only useful for troubleshooting.<br> 353 * The per-application based SMS control checks sentIntent. If sentIntent 354 * is NULL the caller will be checked against all unknown applications, 355 * which cause smaller number of SMS to be sent in checking period. 356 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 357 * broadcast when the message is delivered to the recipient. The 358 * raw pdu of the status report is in the extended data ("pdu"). 359 * 360 * @throws IllegalArgumentException if destinationAddress or data are empty 361 */ 362 public void sendDataMessage( 363 String destinationAddress, String scAddress, short destinationPort, 364 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 365 sendDataMessage(getPreferredSmsSubscription(), 366 destinationAddress, scAddress, destinationPort, 367 data, sentIntent, deliveryIntent); 368 } 369 370 /** 371 * Send a data based SMS to a specific application port. 372 * 373 * @param destinationAddress the address to send the message to 374 * @param scAddress is the service center address or null to use 375 * the current default SMSC 376 * @param destinationPort the port to deliver the message to 377 * @param data the body of the message to send 378 * @param sentIntent if not NULL this <code>PendingIntent</code> is 379 * broadcast when the message is successfully sent, or failed. 380 * The result code will be <code>Activity.RESULT_OK</code> for success, 381 * or one of these errors:<br> 382 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 383 * <code>RESULT_ERROR_RADIO_OFF</code><br> 384 * <code>RESULT_ERROR_NULL_PDU</code><br> 385 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 386 * the extra "errorCode" containing a radio technology specific value, 387 * generally only useful for troubleshooting.<br> 388 * The per-application based SMS control checks sentIntent. If sentIntent 389 * is NULL the caller will be checked against all unknown applications, 390 * which cause smaller number of SMS to be sent in checking period. 391 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 392 * broadcast when the message is delivered to the recipient. The 393 * raw pdu of the status report is in the extended data ("pdu"). 394 * @param subId on which the SMS has to be sent. 395 * 396 * @throws IllegalArgumentException if destinationAddress or data are empty 397 */ 398 /** @hide */ 399 public void sendDataMessage(long subId, 400 String destinationAddress, String scAddress, short destinationPort, 401 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 402 if (TextUtils.isEmpty(destinationAddress)) { 403 throw new IllegalArgumentException("Invalid destinationAddress"); 404 } 405 406 if (data == null || data.length == 0) { 407 throw new IllegalArgumentException("Invalid message data"); 408 } 409 410 try { 411 ISms iccISms = getISmsServiceOrThrow(); 412 iccISms.sendData(ActivityThread.currentPackageName(), 413 destinationAddress, scAddress, destinationPort & 0xFFFF, 414 data, sentIntent, deliveryIntent); 415 } catch (RemoteException ex) { 416 // ignore it 417 } 418 } 419 420 /** 421 * Get the default instance of the SmsManager 422 * 423 * @return the default instance of the SmsManager 424 */ 425 public static SmsManager getDefault() { 426 return sInstance; 427 } 428 429 private SmsManager() { 430 //nothing 431 } 432 433 /** 434 * Returns the ISms service, or throws an UnsupportedOperationException if 435 * the service does not exist. 436 */ 437 private static ISms getISmsServiceOrThrow() { 438 ISms iccISms = getISmsService(); 439 if (iccISms == null) { 440 throw new UnsupportedOperationException("Sms is not supported"); 441 } 442 return iccISms; 443 } 444 445 private static ISms getISmsService() { 446 return ISms.Stub.asInterface(ServiceManager.getService("isms")); 447 } 448 449 /** 450 * Copy a raw SMS PDU to the ICC. 451 * ICC (Integrated Circuit Card) is the card of the device. 452 * For example, this can be the SIM or USIM for GSM. 453 * 454 * @param smsc the SMSC for this message, or NULL for the default SMSC 455 * @param pdu the raw PDU to store 456 * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, 457 * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) 458 * @return true for success 459 * 460 * @throws IllegalArgumentException if pdu is NULL 461 * {@hide} 462 */ 463 public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) { 464 return copyMessageToIcc(getPreferredSmsSubscription(), smsc, pdu, status); 465 } 466 467 /** 468 * Copy a raw SMS PDU to the ICC on subId. 469 * ICC (Integrated Circuit Card) is the card of the device. 470 * For example, this can be the SIM or USIM for GSM. 471 * 472 * @param smsc the SMSC for this message, or NULL for the default SMSC 473 * @param pdu the raw PDU to store 474 * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, 475 * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) 476 * @param subId from which SMS has to be copied. 477 * @return true for success 478 * 479 * @throws IllegalArgumentException if pdu is NULL 480 * {@hide} 481 */ 482 483 /** @hide */ 484 public boolean copyMessageToIcc(long subId, byte[] smsc, byte[] pdu, int status) { 485 boolean success = false; 486 487 if (null == pdu) { 488 throw new IllegalArgumentException("pdu is NULL"); 489 } 490 try { 491 ISms iccISms = getISmsService(); 492 if (iccISms != null) { 493 success = iccISms.copyMessageToIccEf(ActivityThread.currentPackageName(), 494 status, pdu, smsc); 495 } 496 } catch (RemoteException ex) { 497 // ignore it 498 } 499 500 return success; 501 } 502 503 /** 504 * Delete the specified message from the ICC. 505 * ICC (Integrated Circuit Card) is the card of the device. 506 * For example, this can be the SIM or USIM for GSM. 507 * 508 * @param messageIndex is the record index of the message on ICC 509 * @return true for success 510 * 511 * {@hide} 512 */ 513 public boolean 514 deleteMessageFromIcc(int messageIndex) { 515 return deleteMessageFromIcc(getPreferredSmsSubscription(), messageIndex); 516 } 517 518 /** 519 * Delete the specified message from the ICC on subId. 520 * ICC (Integrated Circuit Card) is the card of the device. 521 * For example, this can be the SIM or USIM for GSM. 522 * 523 * @param messageIndex is the record index of the message on ICC 524 * @param subId from which SMS has to be deleted. 525 * @return true for success 526 * 527 */ 528 /** @hide */ 529 public boolean 530 deleteMessageFromIcc(long subId, int messageIndex) { 531 boolean success = false; 532 byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1]; 533 Arrays.fill(pdu, (byte)0xff); 534 535 try { 536 ISms iccISms = getISmsService(); 537 if (iccISms != null) { 538 success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(), 539 messageIndex, STATUS_ON_ICC_FREE, pdu); 540 } 541 } catch (RemoteException ex) { 542 // ignore it 543 } 544 545 return success; 546 } 547 548 /** 549 * Update the specified message on the ICC. 550 * ICC (Integrated Circuit Card) is the card of the device. 551 * For example, this can be the SIM or USIM for GSM. 552 * 553 * @param messageIndex record index of message to update 554 * @param newStatus new message status (STATUS_ON_ICC_READ, 555 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 556 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 557 * @param pdu the raw PDU to store 558 * @return true for success 559 * 560 * {@hide} 561 */ 562 public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { 563 return updateMessageOnIcc(getPreferredSmsSubscription(), messageIndex, newStatus, pdu); 564 } 565 566 /** 567 * Update the specified message on the ICC on subId. 568 * ICC (Integrated Circuit Card) is the card of the device. 569 * For example, this can be the SIM or USIM for GSM. 570 * 571 * @param messageIndex record index of message to update 572 * @param newStatus new message status (STATUS_ON_ICC_READ, 573 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 574 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 575 * @param pdu the raw PDU to store 576 * @param subId on which the SMS had to be updated. 577 * @return true for success 578 * 579 */ 580 /** @hide */ 581 public boolean updateMessageOnIcc(long subId, int messageIndex, int newStatus, 582 byte[] pdu) { 583 boolean success = false; 584 585 try { 586 ISms iccISms = getISmsService(); 587 if (iccISms != null) { 588 success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(), 589 messageIndex, newStatus, pdu); 590 } 591 } catch (RemoteException ex) { 592 // ignore it 593 } 594 595 return success; 596 } 597 598 /** 599 * Retrieves all messages currently stored on ICC. 600 * ICC (Integrated Circuit Card) is the card of the device. 601 * For example, this can be the SIM or USIM for GSM. 602 * 603 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects 604 * 605 * {@hide} 606 */ 607 public static ArrayList<SmsMessage> getAllMessagesFromIcc() { 608 return getAllMessagesFromIcc(getPreferredSmsSubscription()); 609 } 610 611 /** 612 * Retrieves all messages currently stored on ICC on the default 613 * subId. 614 * ICC (Integrated Circuit Card) is the card of the device. 615 * For example, this can be the SIM or USIM for GSM. 616 * 617 * @param subId from which the messages had to be retrieved. 618 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects 619 * 620 */ 621 /** @hide */ 622 public static ArrayList<SmsMessage> getAllMessagesFromIcc(long subId) { 623 List<SmsRawData> records = null; 624 625 try { 626 ISms iccISms = getISmsService(); 627 if (iccISms != null) { 628 records = iccISms.getAllMessagesFromIccEf(ActivityThread.currentPackageName()); 629 } 630 } catch (RemoteException ex) { 631 // ignore it 632 } 633 634 return createMessageListFromRawRecords(records); 635 } 636 637 /** 638 * Enable reception of cell broadcast (SMS-CB) messages with the given 639 * message identifier. Note that if two different clients enable the same 640 * message identifier, they must both disable it for the device to stop 641 * receiving those messages. All received messages will be broadcast in an 642 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 643 * Note: This call is blocking, callers may want to avoid calling it from 644 * the main thread of an application. 645 * 646 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 647 * or C.R1001-G (3GPP2) 648 * @return true if successful, false otherwise 649 * @see #disableCellBroadcast(int) 650 * 651 * {@hide} 652 */ 653 public boolean enableCellBroadcast(int messageIdentifier) { 654 return enableCellBroadcast(getPreferredSmsSubscription(), messageIdentifier); 655 } 656 657 /** 658 * Enable reception of cell broadcast (SMS-CB) messages with the given 659 * message identifier on a particular subId. 660 * Note that if two different clients enable the same 661 * message identifier, they must both disable it for the device to stop 662 * receiving those messages. All received messages will be broadcast in an 663 * intent with the action "android.provider.telephony.SMS_CB_RECEIVED". 664 * Note: This call is blocking, callers may want to avoid calling it from 665 * the main thread of an application. 666 * 667 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 668 * or C.R1001-G (3GPP2) 669 * @param subId for which the broadcast has to be enabled 670 * @return true if successful, false otherwise 671 * @see #disableCellBroadcast(int) 672 * 673 */ 674 /** @hide */ 675 public boolean enableCellBroadcast(long subId, int messageIdentifier) { 676 boolean success = false; 677 678 try { 679 ISms iccISms = getISmsService(); 680 if (iccISms != null) { 681 success = iccISms.enableCellBroadcast(messageIdentifier); 682 } 683 } catch (RemoteException ex) { 684 // ignore it 685 } 686 687 return success; 688 } 689 690 /** 691 * Disable reception of cell broadcast (SMS-CB) messages with the given 692 * message identifier. Note that if two different clients enable the same 693 * message identifier, they must both disable it for the device to stop 694 * receiving those messages. 695 * Note: This call is blocking, callers may want to avoid calling it from 696 * the main thread of an application. 697 * 698 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 699 * or C.R1001-G (3GPP2) 700 * @return true if successful, false otherwise 701 * 702 * @see #enableCellBroadcast(int) 703 * 704 * {@hide} 705 */ 706 public boolean disableCellBroadcast(int messageIdentifier) { 707 return disableCellBroadcast(getPreferredSmsSubscription(), messageIdentifier); 708 } 709 710 /** 711 * Disable reception of cell broadcast (SMS-CB) messages with the given 712 * message identifier on a particular subId. 713 * Note that if two different clients enable the same 714 * message identifier, they must both disable it for the device to stop 715 * receiving those messages. 716 * Note: This call is blocking, callers may want to avoid calling it from 717 * the main thread of an application. 718 * 719 * @param messageIdentifier Message identifier as specified in TS 23.041 720 * @param subId for which the broadcast has to be disabled 721 * @return true if successful, false otherwise 722 * 723 * @see #enableCellBroadcast(int) 724 * 725 */ 726 /** @hide */ 727 public boolean disableCellBroadcast(long subId, int messageIdentifier) { 728 boolean success = false; 729 730 try { 731 ISms iccISms = getISmsService(); 732 if (iccISms != null) { 733 success = iccISms.disableCellBroadcast(messageIdentifier); 734 } 735 } catch (RemoteException ex) { 736 // ignore it 737 } 738 739 return success; 740 } 741 742 /** 743 * Enable reception of cell broadcast (SMS-CB) messages with the given 744 * message identifier range. Note that if two different clients enable the same 745 * message identifier, they must both disable it for the device to stop 746 * receiving those messages. All received messages will be broadcast in an 747 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 748 * Note: This call is blocking, callers may want to avoid calling it from 749 * the main thread of an application. 750 * 751 * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) 752 * or C.R1001-G (3GPP2) 753 * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) 754 * or C.R1001-G (3GPP2) 755 * @return true if successful, false otherwise 756 * @see #disableCellBroadcastRange(int, int) 757 * 758 * @throws IllegalArgumentException if endMessageId < startMessageId 759 * {@hide} 760 */ 761 public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) { 762 return enableCellBroadcastRange(getPreferredSmsSubscription(), startMessageId, 763 endMessageId); 764 } 765 766 /** 767 * Enable reception of cell broadcast (SMS-CB) messages with the given 768 * message identifier range on a particular subId. 769 * Note that if two different clients enable the same 770 * message identifier, they must both disable it for the device to stop 771 * receiving those messages. All received messages will be broadcast in an 772 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 773 * Note: This call is blocking, callers may want to avoid calling it from 774 * the main thread of an application. 775 * 776 * @param startMessageId first message identifier as specified in TS 23.041 777 * @param endMessageId last message identifier as specified in TS 23.041 778 * @return true if successful, false otherwise 779 * @see #disableCellBroadcastRange(int, int) 780 * @throws IllegalArgumentException if endMessageId < startMessageId 781 * 782 */ 783 /** @hide */ 784 public boolean enableCellBroadcastRange(long subId, int startMessageId, 785 int endMessageId) { 786 boolean success = false; 787 788 if (endMessageId < startMessageId) { 789 throw new IllegalArgumentException("endMessageId < startMessageId"); 790 } 791 try { 792 ISms iccISms = getISmsService(); 793 if (iccISms != null) { 794 success = iccISms.enableCellBroadcastRange(startMessageId, endMessageId); 795 } 796 } catch (RemoteException ex) { 797 // ignore it 798 } 799 800 return success; 801 } 802 803 /** 804 * Disable reception of cell broadcast (SMS-CB) messages with the given 805 * message identifier range. Note that if two different clients enable the same 806 * message identifier, they must both disable it for the device to stop 807 * receiving those messages. 808 * Note: This call is blocking, callers may want to avoid calling it from 809 * the main thread of an application. 810 * 811 * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) 812 * or C.R1001-G (3GPP2) 813 * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) 814 * or C.R1001-G (3GPP2) 815 * @return true if successful, false otherwise 816 * 817 * @see #enableCellBroadcastRange(int, int) 818 * 819 * @throws IllegalArgumentException if endMessageId < startMessageId 820 * {@hide} 821 */ 822 public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) { 823 return disableCellBroadcastRange(getPreferredSmsSubscription(), startMessageId, 824 endMessageId); 825 } 826 827 /** 828 * Disable reception of cdma broadcast messages with the given 829 * message identifier range on a particular subId. 830 * Note that if two different clients enable the same 831 * message identifier range, they must both disable it for the device to stop 832 * receiving those messages. 833 * Note: This call is blocking, callers may want to avoid calling it from 834 * the main thread of an application. 835 * 836 * @param startMessageId first message identifier as specified in TS 23.041 837 * @param endMessageId last message identifier as specified in TS 23.041 838 * @return true if successful, false otherwise 839 * 840 * @see #enableCellBroadcastRange(int, int) 841 * @throws IllegalArgumentException if endMessageId < startMessageId 842 * 843 */ 844 /** @hide */ 845 public boolean disableCellBroadcastRange(long subId, int startMessageId, 846 int endMessageId) { 847 boolean success = false; 848 849 if (endMessageId < startMessageId) { 850 throw new IllegalArgumentException("endMessageId < startMessageId"); 851 } 852 try { 853 ISms iccISms = getISmsService(); 854 if (iccISms != null) { 855 success = iccISms.disableCellBroadcastRange(startMessageId, endMessageId); 856 } 857 } catch (RemoteException ex) { 858 // ignore it 859 } 860 861 return success; 862 } 863 864 /** 865 * Create a list of <code>SmsMessage</code>s from a list of RawSmsData 866 * records returned by <code>getAllMessagesFromIcc()</code> 867 * 868 * @param records SMS EF records, returned by 869 * <code>getAllMessagesFromIcc</code> 870 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. 871 */ 872 private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { 873 ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); 874 if (records != null) { 875 int count = records.size(); 876 for (int i = 0; i < count; i++) { 877 SmsRawData data = records.get(i); 878 // List contains all records, including "free" records (null) 879 if (data != null) { 880 SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes()); 881 if (sms != null) { 882 messages.add(sms); 883 } 884 } 885 } 886 } 887 return messages; 888 } 889 890 /** 891 * SMS over IMS is supported if IMS is registered and SMS is supported 892 * on IMS. 893 * 894 * @return true if SMS over IMS is supported, false otherwise 895 * 896 * @see #getImsSmsFormat() 897 * 898 * @hide 899 */ 900 boolean isImsSmsSupported() { 901 return isImsSmsSupported(getPreferredSmsSubscription()); 902 } 903 904 /** @hide */ 905 boolean isImsSmsSupported(long subId) { 906 boolean boSupported = false; 907 try { 908 ISms iccISms = getISmsService(); 909 if (iccISms != null) { 910 boSupported = iccISms.isImsSmsSupported(); 911 } 912 } catch (RemoteException ex) { 913 // ignore it 914 } 915 return boSupported; 916 } 917 918 /** 919 * Gets SMS format supported on IMS. SMS over IMS format is 920 * either 3GPP or 3GPP2. 921 * 922 * @return SmsMessage.FORMAT_3GPP, 923 * SmsMessage.FORMAT_3GPP2 924 * or SmsMessage.FORMAT_UNKNOWN 925 * 926 * @see #isImsSmsSupported() 927 * 928 * @hide 929 */ 930 String getImsSmsFormat() { 931 return getImsSmsFormat(getPreferredSmsSubscription()); 932 } 933 934 /** @hide */ 935 String getImsSmsFormat(long subId) { 936 String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN; 937 try { 938 ISms iccISms = getISmsService(); 939 if (iccISms != null) { 940 format = iccISms.getImsSmsFormat(); 941 } 942 } catch (RemoteException ex) { 943 // ignore it 944 } 945 return format; 946 } 947 948 /** 949 * Get the preferred sms subId 950 * 951 * @return the preferred subId 952 * @hide 953 */ 954 public static long getPreferredSmsSubscription() { 955 ISms iccISms = null; 956 try { 957 iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 958 return (long) iccISms.getPreferredSmsSubscription(); 959 } catch (RemoteException ex) { 960 return DEFAULT_SUB; 961 } catch (NullPointerException ex) { 962 return DEFAULT_SUB; 963 } 964 } 965 966 /** 967 * Get SMS prompt property, enabled or not 968 * 969 * @return true if enabled, false otherwise 970 * @hide 971 */ 972 public boolean isSMSPromptEnabled() { 973 ISms iccISms = null; 974 try { 975 iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 976 return iccISms.isSMSPromptEnabled(); 977 } catch (RemoteException ex) { 978 return false; 979 } catch (NullPointerException ex) { 980 return false; 981 } 982 } 983 984 // see SmsMessage.getStatusOnIcc 985 986 /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 987 static public final int STATUS_ON_ICC_FREE = 0; 988 989 /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 990 static public final int STATUS_ON_ICC_READ = 1; 991 992 /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 993 static public final int STATUS_ON_ICC_UNREAD = 3; 994 995 /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 996 static public final int STATUS_ON_ICC_SENT = 5; 997 998 /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 999 static public final int STATUS_ON_ICC_UNSENT = 7; 1000 1001 // SMS send failure result codes 1002 1003 /** Generic failure cause */ 1004 static public final int RESULT_ERROR_GENERIC_FAILURE = 1; 1005 /** Failed because radio was explicitly turned off */ 1006 static public final int RESULT_ERROR_RADIO_OFF = 2; 1007 /** Failed because no pdu provided */ 1008 static public final int RESULT_ERROR_NULL_PDU = 3; 1009 /** Failed because service is currently unavailable */ 1010 static public final int RESULT_ERROR_NO_SERVICE = 4; 1011 /** Failed because we reached the sending queue limit. {@hide} */ 1012 static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5; 1013 /** Failed because FDN is enabled. {@hide} */ 1014 static public final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; 1015 1016 /** 1017 * Send an MMS message 1018 * 1019 * @param pdu the MMS message encoded in standard MMS PDU format 1020 * @param locationUrl the optional location url where message should be sent to 1021 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1022 * broadcast when the message is successfully sent, or failed 1023 * @throws IllegalArgumentException if pdu is empty 1024 * @hide 1025 */ 1026 public void sendMultimediaMessage(byte[] pdu, String locationUrl, PendingIntent sentIntent) { 1027 sendMultimediaMessage(getPreferredSmsSubscription(), pdu, locationUrl, sentIntent); 1028 } 1029 1030 /** 1031 * Send an MMS message 1032 * 1033 * @param subId the SIM id 1034 * @param pdu the MMS message encoded in standard MMS PDU format 1035 * @param locationUrl the optional location url where message should be sent to 1036 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1037 * broadcast when the message is successfully sent, or failed 1038 * @throws IllegalArgumentException if pdu is empty 1039 * @hide 1040 */ 1041 public void sendMultimediaMessage(long subId, byte[] pdu, String locationUrl, 1042 PendingIntent sentIntent) { 1043 if (pdu == null || pdu.length == 0) { 1044 throw new IllegalArgumentException("Empty or zero length PDU"); 1045 } 1046 try { 1047 final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1048 if (iMms == null) { 1049 return; 1050 } 1051 iMms.sendMessage(subId, ActivityThread.currentPackageName(), pdu, locationUrl, 1052 sentIntent); 1053 } catch (RemoteException e) { 1054 // Ignore it 1055 } 1056 } 1057 1058 /** 1059 * Download an MMS message from carrier by a given location URL 1060 * 1061 * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained 1062 * from the MMS WAP push notification 1063 * @param downloadedIntent if not NULL this <code>PendingIntent</code> is 1064 * broadcast when the message is downloaded, or the download is failed 1065 * @throws IllegalArgumentException if locationUrl is empty 1066 * {@hide} 1067 */ 1068 public void downloadMultimediaMessage(String locationUrl, PendingIntent downloadedIntent) { 1069 downloadMultimediaMessage(getPreferredSmsSubscription(), locationUrl, downloadedIntent); 1070 } 1071 1072 /** 1073 * Download an MMS message from carrier by a given location URL 1074 * 1075 * @param subId the SIM id 1076 * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained 1077 * from the MMS WAP push notification 1078 * @param downloadedIntent if not NULL this <code>PendingIntent</code> is 1079 * broadcast when the message is downloaded, or the download is failed 1080 * @throws IllegalArgumentException if locationUrl is empty 1081 * @hide 1082 */ 1083 public void downloadMultimediaMessage(long subId, String locationUrl, 1084 PendingIntent downloadedIntent) { 1085 if (TextUtils.isEmpty(locationUrl)) { 1086 throw new IllegalArgumentException("Empty MMS location URL"); 1087 } 1088 try { 1089 final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1090 if (iMms == null) { 1091 return; 1092 } 1093 iMms.downloadMessage(subId, ActivityThread.currentPackageName(), locationUrl, 1094 downloadedIntent); 1095 } catch (RemoteException e) { 1096 // Ignore it 1097 } 1098 } 1099 1100 // MMS send/download failure result codes 1101 /**@hide*/ 1102 public static final int MMS_ERROR_UNSPECIFIED = 1; 1103 /**@hide*/ 1104 public static final int MMS_ERROR_INVALID_APN = 2; 1105 /**@hide*/ 1106 public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; 1107 /**@hide*/ 1108 public static final int MMS_ERROR_HTTP_FAILURE = 4; 1109 1110 // Intent extra name for result data 1111 /**@hide*/ 1112 public static final String MMS_EXTRA_DATA = "data"; 1113 1114 /** 1115 * Update the status of a pending (send-by-IP) MMS message handled by the carrier app. 1116 * If the carrier app fails to send this message, it would be resent via carrier network. 1117 * 1118 * @param messageRef the reference number of the MMS message. 1119 * @param success True if and only if the message was sent successfully. If its value is 1120 * false, this message should be resent via carrier network 1121 * {@hide} 1122 */ 1123 public void updateMmsSendStatus(int messageRef, boolean success) { 1124 try { 1125 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1126 if (iMms == null) { 1127 return; 1128 } 1129 iMms.updateMmsSendStatus(messageRef, success); 1130 } catch (RemoteException ex) { 1131 // ignore it 1132 } 1133 } 1134 1135 /** 1136 * Update the status of a pending (download-by-IP) MMS message handled by the carrier app. 1137 * If the carrier app fails to download this message, it would be re-downloaded via carrier 1138 * network. 1139 * 1140 * @param messageRef the reference number of the MMS message. 1141 * @param pdu non-empty if downloaded successfully, otherwise, it is empty and the message 1142 * will be downloaded via carrier network 1143 * {@hide} 1144 */ 1145 public void updateMmsDownloadStatus(int messageRef, byte[] pdu) { 1146 try { 1147 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1148 if (iMms == null) { 1149 return; 1150 } 1151 iMms.updateMmsDownloadStatus(messageRef, pdu); 1152 } catch (RemoteException ex) { 1153 // ignore it 1154 } 1155 } 1156 1157 /** 1158 * Import a text message into system's SMS store 1159 * 1160 * @param address the destination(source) address of the sent(received) message 1161 * @param type the type of the message 1162 * @param text the message text 1163 * @param timestampMillis the message timestamp in milliseconds 1164 * @param seen if the message is seen 1165 * @param read if the message is read 1166 * @return the message URI, null if failed 1167 * {@hide} 1168 */ 1169 public Uri importTextMessage(String address, int type, String text, long timestampMillis, 1170 boolean seen, boolean read) { 1171 try { 1172 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1173 if (iMms != null) { 1174 return iMms.importTextMessage(ActivityThread.currentPackageName(), 1175 address, type, text, timestampMillis, seen, read); 1176 } 1177 } catch (RemoteException ex) { 1178 // ignore it 1179 } 1180 return null; 1181 } 1182 1183 /** Represents the received SMS message for importing */ 1184 /**{@hide}*/ 1185 public static final int SMS_TYPE_INCOMING = 0; 1186 /** Represents the sent SMS message for importing */ 1187 /**{@hide}*/ 1188 public static final int SMS_TYPE_OUTGOING = 1; 1189 1190 /** 1191 * Import a multimedia message into system's MMS store. Only the following PDU type is 1192 * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind 1193 * 1194 * @param pdu the PDU of the message to import 1195 * @param messageId the optional message id. Use null if not specifying 1196 * @param timestampSecs the optional message timestamp. Use -1 if not specifying 1197 * @param seen if the message is seen 1198 * @param read if the message is read 1199 * @return the message URI, null if failed 1200 * @throws IllegalArgumentException if pdu is empty 1201 * {@hide} 1202 */ 1203 public Uri importMultimediaMessage(byte[] pdu, String messageId, long timestampSecs, 1204 boolean seen, boolean read) { 1205 if (pdu == null || pdu.length == 0) { 1206 throw new IllegalArgumentException("Empty or zero length PDU"); 1207 } 1208 try { 1209 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1210 if (iMms != null) { 1211 return iMms.importMultimediaMessage(ActivityThread.currentPackageName(), 1212 pdu, messageId, timestampSecs, seen, read); 1213 } 1214 } catch (RemoteException ex) { 1215 // ignore it 1216 } 1217 return null; 1218 } 1219 1220 /** 1221 * Delete a system stored SMS or MMS message 1222 * 1223 * @param messageUri the URI of the stored message 1224 * @return true if deletion is successful, false otherwise 1225 * @throws IllegalArgumentException if messageUri is empty 1226 * {@hide} 1227 */ 1228 public boolean deleteStoredMessage(Uri messageUri) { 1229 if (messageUri == null) { 1230 throw new IllegalArgumentException("Empty message URI"); 1231 } 1232 try { 1233 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1234 if (iMms != null) { 1235 return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri); 1236 } 1237 } catch (RemoteException ex) { 1238 // ignore it 1239 } 1240 return false; 1241 } 1242 1243 /** 1244 * Delete a system stored SMS or MMS thread 1245 * 1246 * @param conversationId the ID of the message conversation 1247 * @return true if deletion is successful, false otherwise 1248 * {@hide} 1249 */ 1250 public boolean deleteStoredConversation(long conversationId) { 1251 try { 1252 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1253 if (iMms != null) { 1254 return iMms.deleteStoredConversation( 1255 ActivityThread.currentPackageName(), conversationId); 1256 } 1257 } catch (RemoteException ex) { 1258 // ignore it 1259 } 1260 return false; 1261 } 1262 1263 /** 1264 * Update the status properties of a system stored SMS or MMS message, e.g. 1265 * the read status of a message, etc. 1266 * 1267 * @param messageUri the URI of the stored message 1268 * @param statusValues a list of status properties in key-value pairs to update 1269 * @return true if deletion is successful, false otherwise 1270 * @throws IllegalArgumentException if messageUri is empty 1271 * {@hide} 1272 */ 1273 public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) { 1274 if (messageUri == null) { 1275 throw new IllegalArgumentException("Empty message URI"); 1276 } 1277 try { 1278 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1279 if (iMms != null) { 1280 return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(), 1281 messageUri, statusValues); 1282 } 1283 } catch (RemoteException ex) { 1284 // ignore it 1285 } 1286 return false; 1287 } 1288 1289 /** Message status property: whether the message has been seen. 1 means seen, 0 not*/ 1290 /**{@hide}*/ 1291 public static final String MESSAGE_STATUS_SEEN = "seen"; 1292 /** Message status property: whether the message has been read. 1 means read, 0 not*/ 1293 /**{@hide}*/ 1294 public static final String MESSAGE_STATUS_READ = "read"; 1295 /** Message status property: whether the message has been archived. 1 means archived, 0 not*/ 1296 /**{@hide}*/ 1297 public static final String MESSAGE_STATUS_ARCHIVED = "archived"; 1298 1299 /** 1300 * Add a text message draft to system SMS store 1301 * 1302 * @param address the destination address of message 1303 * @param text the body of the message to send 1304 * @return the URI of the stored draft message 1305 * {@hide} 1306 */ 1307 public Uri addTextMessageDraft(String address, String text) { 1308 try { 1309 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1310 if (iMms != null) { 1311 return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text); 1312 } 1313 } catch (RemoteException ex) { 1314 // ignore it 1315 } 1316 return null; 1317 } 1318 1319 /** 1320 * Add a multimedia message draft to system MMS store 1321 * 1322 * @param pdu the PDU data of the draft MMS 1323 * @return the URI of the stored draft message 1324 * @throws IllegalArgumentException if pdu is empty 1325 * {@hide} 1326 */ 1327 public Uri addMultimediaMessageDraft(byte[] pdu) { 1328 if (pdu == null || pdu.length == 0) { 1329 throw new IllegalArgumentException("Empty or zero length PDU"); 1330 } 1331 try { 1332 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1333 if (iMms != null) { 1334 return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(), pdu); 1335 } 1336 } catch (RemoteException ex) { 1337 // ignore it 1338 } 1339 return null; 1340 } 1341 1342 /** 1343 * Send a system stored text message. 1344 * 1345 * You can only send a failed text message or a draft text message. 1346 * 1347 * @param messageUri the URI of the stored message 1348 * @param scAddress is the service center address or null to use the current default SMSC 1349 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1350 * broadcast when the message is successfully sent, or failed. 1351 * The result code will be <code>Activity.RESULT_OK</code> for success, 1352 * or one of these errors:<br> 1353 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 1354 * <code>RESULT_ERROR_RADIO_OFF</code><br> 1355 * <code>RESULT_ERROR_NULL_PDU</code><br> 1356 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 1357 * the extra "errorCode" containing a radio technology specific value, 1358 * generally only useful for troubleshooting.<br> 1359 * The per-application based SMS control checks sentIntent. If sentIntent 1360 * is NULL the caller will be checked against all unknown applications, 1361 * which cause smaller number of SMS to be sent in checking period. 1362 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1363 * broadcast when the message is delivered to the recipient. The 1364 * raw pdu of the status report is in the extended data ("pdu"). 1365 * 1366 * @throws IllegalArgumentException if messageUri is empty 1367 * 1368 * {@hide} 1369 */ 1370 public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent, 1371 PendingIntent deliveryIntent) { 1372 sendStoredTextMessage(getPreferredSmsSubscription(), messageUri, scAddress, sentIntent, 1373 deliveryIntent); 1374 } 1375 1376 /** 1377 * Send a system stored text message. 1378 * 1379 * You can only send a failed text message or a draft text message. 1380 * 1381 * @param subId the SIM id 1382 * @param messageUri the URI of the stored message 1383 * @param scAddress is the service center address or null to use the current default SMSC 1384 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1385 * broadcast when the message is successfully sent, or failed. 1386 * The result code will be <code>Activity.RESULT_OK</code> for success, 1387 * or one of these errors:<br> 1388 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 1389 * <code>RESULT_ERROR_RADIO_OFF</code><br> 1390 * <code>RESULT_ERROR_NULL_PDU</code><br> 1391 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 1392 * the extra "errorCode" containing a radio technology specific value, 1393 * generally only useful for troubleshooting.<br> 1394 * The per-application based SMS control checks sentIntent. If sentIntent 1395 * is NULL the caller will be checked against all unknown applications, 1396 * which cause smaller number of SMS to be sent in checking period. 1397 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1398 * broadcast when the message is delivered to the recipient. The 1399 * raw pdu of the status report is in the extended data ("pdu"). 1400 * 1401 * @throws IllegalArgumentException if messageUri is empty 1402 * 1403 * {@hide} 1404 */ 1405 public void sendStoredTextMessage(long subId, Uri messageUri, String scAddress, 1406 PendingIntent sentIntent, PendingIntent deliveryIntent) { 1407 if (messageUri == null) { 1408 throw new IllegalArgumentException("Empty message URI"); 1409 } 1410 try { 1411 ISms iccISms = getISmsServiceOrThrow(); 1412 iccISms.sendStoredText(subId, ActivityThread.currentPackageName(), messageUri, 1413 scAddress, sentIntent, deliveryIntent); 1414 } catch (RemoteException ex) { 1415 // ignore it 1416 } 1417 } 1418 1419 /** 1420 * Send a system stored multi-part text message. 1421 * 1422 * You can only send a failed text message or a draft text message. 1423 * The provided <code>PendingIntent</code> lists should match the part number of the 1424 * divided text of the stored message by using <code>divideMessage</code> 1425 * 1426 * @param messageUri the URI of the stored message 1427 * @param scAddress is the service center address or null to use 1428 * the current default SMSC 1429 * @param sentIntents if not null, an <code>ArrayList</code> of 1430 * <code>PendingIntent</code>s (one for each message part) that is 1431 * broadcast when the corresponding message part has been sent. 1432 * The result code will be <code>Activity.RESULT_OK</code> for success, 1433 * or one of these errors:<br> 1434 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 1435 * <code>RESULT_ERROR_RADIO_OFF</code><br> 1436 * <code>RESULT_ERROR_NULL_PDU</code><br> 1437 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 1438 * the extra "errorCode" containing a radio technology specific value, 1439 * generally only useful for troubleshooting.<br> 1440 * The per-application based SMS control checks sentIntent. If sentIntent 1441 * is NULL the caller will be checked against all unknown applications, 1442 * which cause smaller number of SMS to be sent in checking period. 1443 * @param deliveryIntents if not null, an <code>ArrayList</code> of 1444 * <code>PendingIntent</code>s (one for each message part) that is 1445 * broadcast when the corresponding message part has been delivered 1446 * to the recipient. The raw pdu of the status report is in the 1447 * extended data ("pdu"). 1448 * 1449 * @throws IllegalArgumentException if messageUri is empty 1450 * 1451 * {@hide} 1452 */ 1453 public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress, 1454 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 1455 sendStoredMultipartTextMessage(getPreferredSmsSubscription(), messageUri, scAddress, 1456 sentIntents, deliveryIntents); 1457 } 1458 1459 /** 1460 * Send a system stored multi-part text message. 1461 * 1462 * This is used for sending a previously sent, but failed-to-send, message or 1463 * for sending a text message that has been stored as a draft. 1464 * The provided <code>PendingIntent</code> lists should match the part number of the 1465 * divided text of the stored message by using <code>divideMessage</code> 1466 * 1467 * @param subId the SIM id 1468 * @param messageUri the URI of the stored message 1469 * @param scAddress is the service center address or null to use 1470 * the current default SMSC 1471 * @param sentIntents if not null, an <code>ArrayList</code> of 1472 * <code>PendingIntent</code>s (one for each message part) that is 1473 * broadcast when the corresponding message part has been sent. 1474 * The result code will be <code>Activity.RESULT_OK</code> for success, 1475 * or one of these errors:<br> 1476 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 1477 * <code>RESULT_ERROR_RADIO_OFF</code><br> 1478 * <code>RESULT_ERROR_NULL_PDU</code><br> 1479 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 1480 * the extra "errorCode" containing a radio technology specific value, 1481 * generally only useful for troubleshooting.<br> 1482 * The per-application based SMS control checks sentIntent. If sentIntent 1483 * is NULL the caller will be checked against all unknown applications, 1484 * which cause smaller number of SMS to be sent in checking period. 1485 * @param deliveryIntents if not null, an <code>ArrayList</code> of 1486 * <code>PendingIntent</code>s (one for each message part) that is 1487 * broadcast when the corresponding message part has been delivered 1488 * to the recipient. The raw pdu of the status report is in the 1489 * extended data ("pdu"). 1490 * 1491 * @throws IllegalArgumentException if messageUri is empty 1492 * 1493 * {@hide} 1494 */ 1495 public void sendStoredMultipartTextMessage(long subId, Uri messageUri, String scAddress, 1496 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 1497 if (messageUri == null) { 1498 throw new IllegalArgumentException("Empty message URI"); 1499 } 1500 try { 1501 ISms iccISms = getISmsServiceOrThrow(); 1502 iccISms.sendStoredMultipartText(subId, ActivityThread.currentPackageName(), messageUri, 1503 scAddress, sentIntents, deliveryIntents); 1504 } catch (RemoteException ex) { 1505 // ignore it 1506 } 1507 } 1508 1509 /** 1510 * Send a system stored MMS message 1511 * 1512 * This is used for sending a previously sent, but failed-to-send, message or 1513 * for sending a text message that has been stored as a draft. 1514 * 1515 * @param messageUri the URI of the stored message 1516 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1517 * broadcast when the message is successfully sent, or failed 1518 * @throws IllegalArgumentException if messageUri is empty 1519 * {@hide} 1520 */ 1521 public void sendStoredMultimediaMessage(Uri messageUri, PendingIntent sentIntent) { 1522 sendStoredMultimediaMessage(getPreferredSmsSubscription(), messageUri, sentIntent); 1523 } 1524 1525 /** 1526 * Send a system stored MMS message 1527 * 1528 * This is used for sending a previously sent, but failed-to-send, message or 1529 * for sending a text message that has been stored as a draft. 1530 * 1531 * @param subId the SIM id 1532 * @param messageUri the URI of the stored message 1533 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1534 * broadcast when the message is successfully sent, or failed 1535 * @throws IllegalArgumentException if messageUri is empty 1536 * {@hide} 1537 */ 1538 public void sendStoredMultimediaMessage(long subId, Uri messageUri, PendingIntent sentIntent) { 1539 if (messageUri == null) { 1540 throw new IllegalArgumentException("Empty message URI"); 1541 } 1542 try { 1543 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1544 if (iMms != null) { 1545 iMms.sendStoredMessage(subId, ActivityThread.currentPackageName(), messageUri, 1546 sentIntent); 1547 } 1548 } catch (RemoteException ex) { 1549 // ignore it 1550 } 1551 } 1552} 1553