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