SmsManager.java revision d6bf802a1afd6dbd99b35804ec0ec565f2ac8e9e
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.os.RemoteException; 22import android.os.ServiceManager; 23import android.text.TextUtils; 24import android.util.Log; 25 26import com.android.internal.telephony.ISms; 27import com.android.internal.telephony.SmsRawData; 28import com.android.internal.telephony.IMms; 29import com.android.internal.telephony.uicc.IccConstants; 30 31import java.util.ArrayList; 32import java.util.Arrays; 33import java.util.List; 34 35/* 36 * TODO(code review): Curious question... Why are a lot of these 37 * methods not declared as static, since they do not seem to require 38 * any local object state? Presumably this cannot be changed without 39 * interfering with the API... 40 */ 41 42/** 43 * Manages SMS operations such as sending data, text, and pdu SMS messages. 44 * Get this object by calling the static method {@link #getDefault()}. 45 * 46 * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19) 47 * and higher, see {@link android.provider.Telephony}. 48 */ 49public final class SmsManager { 50 /** Singleton object constructed during class initialization. */ 51 private static final SmsManager sInstance = new SmsManager(); 52 private static final int DEFAULT_SUB = 0; 53 54 /** 55 * Send a text based SMS. 56 * 57 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 58 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 59 * 60 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 61 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 62 * writes messages sent using this method to the SMS Provider (the default SMS app is always 63 * responsible for writing its sent messages to the SMS Provider). For information about 64 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 65 * 66 * 67 * @param destinationAddress the address to send the message to 68 * @param scAddress is the service center address or null to use 69 * the current default SMSC 70 * @param text the body of the message to send 71 * @param sentIntent if not NULL this <code>PendingIntent</code> is 72 * broadcast when the message is successfully sent, or failed. 73 * The result code will be <code>Activity.RESULT_OK</code> for success, 74 * or one of these errors:<br> 75 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 76 * <code>RESULT_ERROR_RADIO_OFF</code><br> 77 * <code>RESULT_ERROR_NULL_PDU</code><br> 78 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 79 * the extra "errorCode" containing a radio technology specific value, 80 * generally only useful for troubleshooting.<br> 81 * The per-application based SMS control checks sentIntent. If sentIntent 82 * is NULL the caller will be checked against all unknown applications, 83 * which cause smaller number of SMS to be sent in checking period. 84 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 85 * broadcast when the message is delivered to the recipient. The 86 * raw pdu of the status report is in the extended data ("pdu"). 87 * 88 * @throws IllegalArgumentException if destinationAddress or text are empty 89 */ 90 public void sendTextMessage( 91 String destinationAddress, String scAddress, String text, 92 PendingIntent sentIntent, PendingIntent deliveryIntent) { 93 sendTextMessage(getPreferredSmsSubscription(), destinationAddress, scAddress, text, 94 sentIntent, deliveryIntent); 95 } 96 97 /** 98 * Send a text based SMS. 99 * 100 * @param destinationAddress the address to send the message to 101 * @param scAddress is the service center address or null to use 102 * the current default SMSC 103 * @param text the body of the message to send 104 * @param sentIntent if not NULL this <code>PendingIntent</code> is 105 * broadcast when the message is successfully sent, or failed. 106 * The result code will be <code>Activity.RESULT_OK</code> for success, 107 * or one of these errors:<br> 108 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 109 * <code>RESULT_ERROR_RADIO_OFF</code><br> 110 * <code>RESULT_ERROR_NULL_PDU</code><br> 111 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 112 * the extra "errorCode" containing a radio technology specific value, 113 * generally only useful for troubleshooting.<br> 114 * The per-application based SMS control checks sentIntent. If sentIntent 115 * is NULL the caller will be checked against all unknown applications, 116 * which cause smaller number of SMS to be sent in checking period. 117 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 118 * broadcast when the message is delivered to the recipient. The 119 * raw pdu of the status report is in the extended data ("pdu"). 120 * @param subId on which the SMS has to be sent. 121 * 122 * @throws IllegalArgumentException if destinationAddress or text are empty 123 * 124 */ 125 /** @hide */ 126 public void sendTextMessage( 127 long subId, String destinationAddress, String scAddress, String text, 128 PendingIntent sentIntent, PendingIntent deliveryIntent) { 129 if (TextUtils.isEmpty(destinationAddress)) { 130 throw new IllegalArgumentException("Invalid destinationAddress"); 131 } 132 133 if (TextUtils.isEmpty(text)) { 134 throw new IllegalArgumentException("Invalid message body"); 135 } 136 137 try { 138 ISms iccISms = getISmsServiceOrThrow(); 139 iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress, 140 scAddress, text, sentIntent, deliveryIntent); 141 } catch (RemoteException ex) { 142 // ignore it 143 } 144 } 145 146 /** 147 * TODO Move this to new CarrierSmsManager class. 148 * 149 * Inject an SMS PDU into the android application framework. 150 * 151 * @param pdu is the byte array of pdu to be injected into android application framework 152 * @param format is the format of SMS pdu (3gpp or 3gpp2) 153 * @param receivedIntent if not NULL this <code>PendingIntent</code> is 154 * broadcast when the message is successfully received by the 155 * android application framework. This intent is broadcasted at 156 * the same time an SMS received from radio is acknowledged back. 157 * 158 * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2. 159 * {@hide} 160 */ 161 public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) { 162 if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) { 163 // Format must be either 3gpp or 3gpp2. 164 throw new IllegalArgumentException( 165 "Invalid pdu format. format must be either 3gpp or 3gpp2"); 166 } 167 try { 168 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 169 if (iccISms != null) { 170 iccISms.injectSmsPdu(pdu, format, receivedIntent); 171 } 172 } catch (RemoteException ex) { 173 // ignore it 174 } 175 } 176 177 /** 178 * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary. 179 * This outbound message was handled by the carrier app. If the carrier app fails to send 180 * this message, it would be resent by PSTN. 181 * 182 * @param messageRef the reference number of the SMS message. 183 * @param success True if and only if the message was sent successfully. If its value is 184 * false, this message should be resent via PSTN. 185 * {@hide} 186 */ 187 public void updateSmsSendStatus(int messageRef, boolean success) { 188 try { 189 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 190 if (iccISms != null) { 191 iccISms.updateSmsSendStatus(messageRef, success); 192 } 193 } catch (RemoteException ex) { 194 // ignore it 195 } 196 } 197 198 /** 199 * Divide a message text into several fragments, none bigger than 200 * the maximum SMS message size. 201 * 202 * @param text the original message. Must not be null. 203 * @return an <code>ArrayList</code> of strings that, in order, 204 * comprise the original message 205 * 206 * @throws IllegalArgumentException if text is null 207 */ 208 public ArrayList<String> divideMessage(String text) { 209 if (null == text) { 210 throw new IllegalArgumentException("text is null"); 211 } 212 return SmsMessage.fragmentText(text); 213 } 214 215 /** 216 * Send a multi-part text based SMS. The callee should have already 217 * divided the message into correctly sized parts by calling 218 * <code>divideMessage</code>. 219 * 220 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 221 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 222 * 223 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 224 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 225 * writes messages sent using this method to the SMS Provider (the default SMS app is always 226 * responsible for writing its sent messages to the SMS Provider). For information about 227 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 228 * 229 * @param destinationAddress the address to send the message to 230 * @param scAddress is the service center address or null to use 231 * the current default SMSC 232 * @param parts an <code>ArrayList</code> of strings that, in order, 233 * comprise the original message 234 * @param sentIntents if not null, an <code>ArrayList</code> of 235 * <code>PendingIntent</code>s (one for each message part) that is 236 * broadcast when the corresponding message part has been sent. 237 * The result code will be <code>Activity.RESULT_OK</code> for success, 238 * or one of these errors:<br> 239 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 240 * <code>RESULT_ERROR_RADIO_OFF</code><br> 241 * <code>RESULT_ERROR_NULL_PDU</code><br> 242 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 243 * the extra "errorCode" containing a radio technology specific value, 244 * generally only useful for troubleshooting.<br> 245 * The per-application based SMS control checks sentIntent. If sentIntent 246 * is NULL the caller will be checked against all unknown applications, 247 * which cause smaller number of SMS to be sent in checking period. 248 * @param deliveryIntents if not null, an <code>ArrayList</code> of 249 * <code>PendingIntent</code>s (one for each message part) that is 250 * broadcast when the corresponding message part has been delivered 251 * to the recipient. The raw pdu of the status report is in the 252 * extended data ("pdu"). 253 * 254 * @throws IllegalArgumentException if destinationAddress or data are empty 255 */ 256 public void sendMultipartTextMessage( 257 String destinationAddress, String scAddress, ArrayList<String> parts, 258 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 259 sendMultipartTextMessage(getPreferredSmsSubscription(), destinationAddress, scAddress, parts, sentIntents, 260 deliveryIntents); 261 } 262 263 /** 264 * Send a multi-part text based SMS. The callee should have already 265 * divided the message into correctly sized parts by calling 266 * <code>divideMessage</code>. 267 * 268 * @param destinationAddress the address to send the message to 269 * @param scAddress is the service center address or null to use 270 * the current default SMSC 271 * @param parts an <code>ArrayList</code> of strings that, in order, 272 * comprise the original message 273 * @param sentIntents if not null, an <code>ArrayList</code> of 274 * <code>PendingIntent</code>s (one for each message part) that is 275 * broadcast when the corresponding message part has been sent. 276 * The result code will be <code>Activity.RESULT_OK</code> for success, 277 * or one of these errors:<br> 278 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 279 * <code>RESULT_ERROR_RADIO_OFF</code><br> 280 * <code>RESULT_ERROR_NULL_PDU</code><br> 281 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 282 * the extra "errorCode" containing a radio technology specific value, 283 * generally only useful for troubleshooting.<br> 284 * The per-application based SMS control checks sentIntent. If sentIntent 285 * is NULL the caller will be checked against all unknown applications, 286 * which cause smaller number of SMS to be sent in checking period. 287 * @param deliveryIntents if not null, an <code>ArrayList</code> of 288 * <code>PendingIntent</code>s (one for each message part) that is 289 * broadcast when the corresponding message part has been delivered 290 * to the recipient. The raw pdu of the status report is in the 291 * extended data ("pdu"). 292 * @param subId on which the SMS has to be sent. 293 * 294 * @throws IllegalArgumentException if destinationAddress or data are empty 295 */ 296 /** @hide */ 297 public void sendMultipartTextMessage(long subId, String destinationAddress, String scAddress, 298 ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, 299 ArrayList<PendingIntent> deliveryIntents) { 300 if (TextUtils.isEmpty(destinationAddress)) { 301 throw new IllegalArgumentException("Invalid destinationAddress"); 302 } 303 if (parts == null || parts.size() < 1) { 304 throw new IllegalArgumentException("Invalid message body"); 305 } 306 307 if (parts.size() > 1) { 308 try { 309 ISms iccISms = getISmsServiceOrThrow(); 310 iccISms.sendMultipartText(ActivityThread.currentPackageName(), 311 destinationAddress, scAddress, parts, 312 sentIntents, deliveryIntents); 313 } catch (RemoteException ex) { 314 // ignore it 315 } 316 } else { 317 PendingIntent sentIntent = null; 318 PendingIntent deliveryIntent = null; 319 if (sentIntents != null && sentIntents.size() > 0) { 320 sentIntent = sentIntents.get(0); 321 } 322 if (deliveryIntents != null && deliveryIntents.size() > 0) { 323 deliveryIntent = deliveryIntents.get(0); 324 } 325 sendTextMessage(destinationAddress, scAddress, parts.get(0), 326 sentIntent, deliveryIntent); 327 } 328 } 329 330 /** 331 * Send a data based SMS to a specific application port. 332 * 333 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 334 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 335 * 336 * @param destinationAddress the address to send the message to 337 * @param scAddress is the service center address or null to use 338 * the current default SMSC 339 * @param destinationPort the port to deliver the message to 340 * @param data the body of the message to send 341 * @param sentIntent if not NULL this <code>PendingIntent</code> is 342 * broadcast when the message is successfully sent, or failed. 343 * The result code will be <code>Activity.RESULT_OK</code> for success, 344 * or one of these errors:<br> 345 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 346 * <code>RESULT_ERROR_RADIO_OFF</code><br> 347 * <code>RESULT_ERROR_NULL_PDU</code><br> 348 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 349 * the extra "errorCode" containing a radio technology specific value, 350 * generally only useful for troubleshooting.<br> 351 * The per-application based SMS control checks sentIntent. If sentIntent 352 * is NULL the caller will be checked against all unknown applications, 353 * which cause smaller number of SMS to be sent in checking period. 354 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 355 * broadcast when the message is delivered to the recipient. The 356 * raw pdu of the status report is in the extended data ("pdu"). 357 * 358 * @throws IllegalArgumentException if destinationAddress or data are empty 359 */ 360 public void sendDataMessage( 361 String destinationAddress, String scAddress, short destinationPort, 362 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 363 sendDataMessage(getPreferredSmsSubscription(), 364 destinationAddress, scAddress, destinationPort, 365 data, sentIntent, deliveryIntent); 366 } 367 368 /** 369 * Send a data based SMS to a specific application port. 370 * 371 * @param destinationAddress the address to send the message to 372 * @param scAddress is the service center address or null to use 373 * the current default SMSC 374 * @param destinationPort the port to deliver the message to 375 * @param data the body of the message to send 376 * @param sentIntent if not NULL this <code>PendingIntent</code> is 377 * broadcast when the message is successfully sent, or failed. 378 * The result code will be <code>Activity.RESULT_OK</code> for success, 379 * or one of these errors:<br> 380 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 381 * <code>RESULT_ERROR_RADIO_OFF</code><br> 382 * <code>RESULT_ERROR_NULL_PDU</code><br> 383 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 384 * the extra "errorCode" containing a radio technology specific value, 385 * generally only useful for troubleshooting.<br> 386 * The per-application based SMS control checks sentIntent. If sentIntent 387 * is NULL the caller will be checked against all unknown applications, 388 * which cause smaller number of SMS to be sent in checking period. 389 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 390 * broadcast when the message is delivered to the recipient. The 391 * raw pdu of the status report is in the extended data ("pdu"). 392 * @param subId on which the SMS has to be sent. 393 * 394 * @throws IllegalArgumentException if destinationAddress or data are empty 395 */ 396 /** @hide */ 397 public void sendDataMessage(long subId, 398 String destinationAddress, String scAddress, short destinationPort, 399 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 400 if (TextUtils.isEmpty(destinationAddress)) { 401 throw new IllegalArgumentException("Invalid destinationAddress"); 402 } 403 404 if (data == null || data.length == 0) { 405 throw new IllegalArgumentException("Invalid message data"); 406 } 407 408 try { 409 ISms iccISms = getISmsServiceOrThrow(); 410 iccISms.sendData(ActivityThread.currentPackageName(), 411 destinationAddress, scAddress, destinationPort & 0xFFFF, 412 data, sentIntent, deliveryIntent); 413 } catch (RemoteException ex) { 414 // ignore it 415 } 416 } 417 418 /** 419 * Get the default instance of the SmsManager 420 * 421 * @return the default instance of the SmsManager 422 */ 423 public static SmsManager getDefault() { 424 return sInstance; 425 } 426 427 private SmsManager() { 428 //nothing 429 } 430 431 /** 432 * Returns the ISms service, or throws an UnsupportedOperationException if 433 * the service does not exist. 434 */ 435 private static ISms getISmsServiceOrThrow() { 436 ISms iccISms = getISmsService(); 437 if (iccISms == null) { 438 throw new UnsupportedOperationException("Sms is not supported"); 439 } 440 return iccISms; 441 } 442 443 private static ISms getISmsService() { 444 return ISms.Stub.asInterface(ServiceManager.getService("isms")); 445 } 446 447 /** 448 * Copy a raw SMS PDU to the ICC. 449 * ICC (Integrated Circuit Card) is the card of the device. 450 * For example, this can be the SIM or USIM for GSM. 451 * 452 * @param smsc the SMSC for this message, or NULL for the default SMSC 453 * @param pdu the raw PDU to store 454 * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, 455 * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) 456 * @return true for success 457 * 458 * @throws IllegalArgumentException if pdu is NULL 459 * {@hide} 460 */ 461 public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) { 462 return copyMessageToIcc(getPreferredSmsSubscription(), smsc, pdu, status); 463 } 464 465 /** 466 * Copy a raw SMS PDU to the ICC on subId. 467 * ICC (Integrated Circuit Card) is the card of the device. 468 * For example, this can be the SIM or USIM for GSM. 469 * 470 * @param smsc the SMSC for this message, or NULL for the default SMSC 471 * @param pdu the raw PDU to store 472 * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, 473 * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) 474 * @param subId from which SMS has to be copied. 475 * @return true for success 476 * 477 * @throws IllegalArgumentException if pdu is NULL 478 * {@hide} 479 */ 480 481 /** @hide */ 482 public boolean copyMessageToIcc(long subId, byte[] smsc, byte[] pdu, int status) { 483 boolean success = false; 484 485 if (null == pdu) { 486 throw new IllegalArgumentException("pdu is NULL"); 487 } 488 try { 489 ISms iccISms = getISmsService(); 490 if (iccISms != null) { 491 success = iccISms.copyMessageToIccEf(ActivityThread.currentPackageName(), 492 status, pdu, smsc); 493 } 494 } catch (RemoteException ex) { 495 // ignore it 496 } 497 498 return success; 499 } 500 501 /** 502 * Delete the specified message from the ICC. 503 * ICC (Integrated Circuit Card) is the card of the device. 504 * For example, this can be the SIM or USIM for GSM. 505 * 506 * @param messageIndex is the record index of the message on ICC 507 * @return true for success 508 * 509 * {@hide} 510 */ 511 public boolean 512 deleteMessageFromIcc(int messageIndex) { 513 return deleteMessageFromIcc(getPreferredSmsSubscription(), messageIndex); 514 } 515 516 /** 517 * Delete the specified message from the ICC on subId. 518 * ICC (Integrated Circuit Card) is the card of the device. 519 * For example, this can be the SIM or USIM for GSM. 520 * 521 * @param messageIndex is the record index of the message on ICC 522 * @param subId from which SMS has to be deleted. 523 * @return true for success 524 * 525 */ 526 /** @hide */ 527 public boolean 528 deleteMessageFromIcc(long subId, int messageIndex) { 529 boolean success = false; 530 byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1]; 531 Arrays.fill(pdu, (byte)0xff); 532 533 try { 534 ISms iccISms = getISmsService(); 535 if (iccISms != null) { 536 success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(), 537 messageIndex, STATUS_ON_ICC_FREE, pdu); 538 } 539 } catch (RemoteException ex) { 540 // ignore it 541 } 542 543 return success; 544 } 545 546 /** 547 * Update the specified message on the ICC. 548 * ICC (Integrated Circuit Card) is the card of the device. 549 * For example, this can be the SIM or USIM for GSM. 550 * 551 * @param messageIndex record index of message to update 552 * @param newStatus new message status (STATUS_ON_ICC_READ, 553 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 554 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 555 * @param pdu the raw PDU to store 556 * @return true for success 557 * 558 * {@hide} 559 */ 560 public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { 561 return updateMessageOnIcc(getPreferredSmsSubscription(), messageIndex, newStatus, pdu); 562 } 563 564 /** 565 * Update the specified message on the ICC on subId. 566 * ICC (Integrated Circuit Card) is the card of the device. 567 * For example, this can be the SIM or USIM for GSM. 568 * 569 * @param messageIndex record index of message to update 570 * @param newStatus new message status (STATUS_ON_ICC_READ, 571 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 572 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 573 * @param pdu the raw PDU to store 574 * @param subId on which the SMS had to be updated. 575 * @return true for success 576 * 577 */ 578 /** @hide */ 579 public boolean updateMessageOnIcc(long subId, int messageIndex, int newStatus, 580 byte[] pdu) { 581 boolean success = false; 582 583 try { 584 ISms iccISms = getISmsService(); 585 if (iccISms != null) { 586 success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(), 587 messageIndex, newStatus, pdu); 588 } 589 } catch (RemoteException ex) { 590 // ignore it 591 } 592 593 return success; 594 } 595 596 /** 597 * Retrieves all messages currently stored on ICC. 598 * ICC (Integrated Circuit Card) is the card of the device. 599 * For example, this can be the SIM or USIM for GSM. 600 * 601 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects 602 * 603 * {@hide} 604 */ 605 public static ArrayList<SmsMessage> getAllMessagesFromIcc() { 606 return getAllMessagesFromIcc(getPreferredSmsSubscription()); 607 } 608 609 /** 610 * Retrieves all messages currently stored on ICC on the default 611 * subId. 612 * ICC (Integrated Circuit Card) is the card of the device. 613 * For example, this can be the SIM or USIM for GSM. 614 * 615 * @param subId from which the messages had to be retrieved. 616 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects 617 * 618 */ 619 /** @hide */ 620 public static ArrayList<SmsMessage> getAllMessagesFromIcc(long subId) { 621 List<SmsRawData> records = null; 622 623 try { 624 ISms iccISms = getISmsService(); 625 if (iccISms != null) { 626 records = iccISms.getAllMessagesFromIccEf(ActivityThread.currentPackageName()); 627 } 628 } catch (RemoteException ex) { 629 // ignore it 630 } 631 632 return createMessageListFromRawRecords(records); 633 } 634 635 /** 636 * Enable reception of cell broadcast (SMS-CB) messages with the given 637 * message identifier. Note that if two different clients enable the same 638 * message identifier, they must both disable it for the device to stop 639 * receiving those messages. All received messages will be broadcast in an 640 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 641 * Note: This call is blocking, callers may want to avoid calling it from 642 * the main thread of an application. 643 * 644 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 645 * or C.R1001-G (3GPP2) 646 * @return true if successful, false otherwise 647 * @see #disableCellBroadcast(int) 648 * 649 * {@hide} 650 */ 651 public boolean enableCellBroadcast(int messageIdentifier) { 652 return enableCellBroadcast(getPreferredSmsSubscription(), messageIdentifier); 653 } 654 655 /** 656 * Enable reception of cell broadcast (SMS-CB) messages with the given 657 * message identifier on a particular subId. 658 * Note that if two different clients enable the same 659 * message identifier, they must both disable it for the device to stop 660 * receiving those messages. All received messages will be broadcast in an 661 * intent with the action "android.provider.telephony.SMS_CB_RECEIVED". 662 * Note: This call is blocking, callers may want to avoid calling it from 663 * the main thread of an application. 664 * 665 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 666 * or C.R1001-G (3GPP2) 667 * @param subId for which the broadcast has to be enabled 668 * @return true if successful, false otherwise 669 * @see #disableCellBroadcast(int) 670 * 671 */ 672 /** @hide */ 673 public boolean enableCellBroadcast(long subId, int messageIdentifier) { 674 boolean success = false; 675 676 try { 677 ISms iccISms = getISmsService(); 678 if (iccISms != null) { 679 success = iccISms.enableCellBroadcast(messageIdentifier); 680 } 681 } catch (RemoteException ex) { 682 // ignore it 683 } 684 685 return success; 686 } 687 688 /** 689 * Disable reception of cell broadcast (SMS-CB) messages with the given 690 * message identifier. Note that if two different clients enable the same 691 * message identifier, they must both disable it for the device to stop 692 * receiving those messages. 693 * Note: This call is blocking, callers may want to avoid calling it from 694 * the main thread of an application. 695 * 696 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 697 * or C.R1001-G (3GPP2) 698 * @return true if successful, false otherwise 699 * 700 * @see #enableCellBroadcast(int) 701 * 702 * {@hide} 703 */ 704 public boolean disableCellBroadcast(int messageIdentifier) { 705 return disableCellBroadcast(getPreferredSmsSubscription(), messageIdentifier); 706 } 707 708 /** 709 * Disable reception of cell broadcast (SMS-CB) messages with the given 710 * message identifier on a particular subId. 711 * Note that if two different clients enable the same 712 * message identifier, they must both disable it for the device to stop 713 * receiving those messages. 714 * Note: This call is blocking, callers may want to avoid calling it from 715 * the main thread of an application. 716 * 717 * @param messageIdentifier Message identifier as specified in TS 23.041 718 * @param subId for which the broadcast has to be disabled 719 * @return true if successful, false otherwise 720 * 721 * @see #enableCellBroadcast(int) 722 * 723 */ 724 /** @hide */ 725 public boolean disableCellBroadcast(long subId, int messageIdentifier) { 726 boolean success = false; 727 728 try { 729 ISms iccISms = getISmsService(); 730 if (iccISms != null) { 731 success = iccISms.disableCellBroadcast(messageIdentifier); 732 } 733 } catch (RemoteException ex) { 734 // ignore it 735 } 736 737 return success; 738 } 739 740 /** 741 * Enable reception of cell broadcast (SMS-CB) messages with the given 742 * message identifier range. Note that if two different clients enable the same 743 * message identifier, they must both disable it for the device to stop 744 * receiving those messages. All received messages will be broadcast in an 745 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 746 * Note: This call is blocking, callers may want to avoid calling it from 747 * the main thread of an application. 748 * 749 * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) 750 * or C.R1001-G (3GPP2) 751 * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) 752 * or C.R1001-G (3GPP2) 753 * @return true if successful, false otherwise 754 * @see #disableCellBroadcastRange(int, int) 755 * 756 * @throws IllegalArgumentException if endMessageId < startMessageId 757 * {@hide} 758 */ 759 public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) { 760 return enableCellBroadcastRange(getPreferredSmsSubscription(), startMessageId, 761 endMessageId); 762 } 763 764 /** 765 * Enable reception of cell broadcast (SMS-CB) messages with the given 766 * message identifier range on a particular subId. 767 * Note that if two different clients enable the same 768 * message identifier, they must both disable it for the device to stop 769 * receiving those messages. All received messages will be broadcast in an 770 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 771 * Note: This call is blocking, callers may want to avoid calling it from 772 * the main thread of an application. 773 * 774 * @param startMessageId first message identifier as specified in TS 23.041 775 * @param endMessageId last message identifier as specified in TS 23.041 776 * @return true if successful, false otherwise 777 * @see #disableCellBroadcastRange(int, int) 778 * @throws IllegalArgumentException if endMessageId < startMessageId 779 * 780 */ 781 /** @hide */ 782 public boolean enableCellBroadcastRange(long subId, int startMessageId, 783 int endMessageId) { 784 boolean success = false; 785 786 if (endMessageId < startMessageId) { 787 throw new IllegalArgumentException("endMessageId < startMessageId"); 788 } 789 try { 790 ISms iccISms = getISmsService(); 791 if (iccISms != null) { 792 success = iccISms.enableCellBroadcastRange(startMessageId, endMessageId); 793 } 794 } catch (RemoteException ex) { 795 // ignore it 796 } 797 798 return success; 799 } 800 801 /** 802 * Disable reception of cell broadcast (SMS-CB) messages with the given 803 * message identifier range. Note that if two different clients enable the same 804 * message identifier, they must both disable it for the device to stop 805 * receiving those messages. 806 * Note: This call is blocking, callers may want to avoid calling it from 807 * the main thread of an application. 808 * 809 * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) 810 * or C.R1001-G (3GPP2) 811 * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) 812 * or C.R1001-G (3GPP2) 813 * @return true if successful, false otherwise 814 * 815 * @see #enableCellBroadcastRange(int, int) 816 * 817 * @throws IllegalArgumentException if endMessageId < startMessageId 818 * {@hide} 819 */ 820 public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) { 821 return disableCellBroadcastRange(getPreferredSmsSubscription(), startMessageId, 822 endMessageId); 823 } 824 825 /** 826 * Disable reception of cdma broadcast messages with the given 827 * message identifier range on a particular subId. 828 * Note that if two different clients enable the same 829 * message identifier range, they must both disable it for the device to stop 830 * receiving those messages. 831 * Note: This call is blocking, callers may want to avoid calling it from 832 * the main thread of an application. 833 * 834 * @param startMessageId first message identifier as specified in TS 23.041 835 * @param endMessageId last message identifier as specified in TS 23.041 836 * @return true if successful, false otherwise 837 * 838 * @see #enableCellBroadcastRange(int, int) 839 * @throws IllegalArgumentException if endMessageId < startMessageId 840 * 841 */ 842 /** @hide */ 843 public boolean disableCellBroadcastRange(long subId, int startMessageId, 844 int endMessageId) { 845 boolean success = false; 846 847 if (endMessageId < startMessageId) { 848 throw new IllegalArgumentException("endMessageId < startMessageId"); 849 } 850 try { 851 ISms iccISms = getISmsService(); 852 if (iccISms != null) { 853 success = iccISms.disableCellBroadcastRange(startMessageId, endMessageId); 854 } 855 } catch (RemoteException ex) { 856 // ignore it 857 } 858 859 return success; 860 } 861 862 /** 863 * Create a list of <code>SmsMessage</code>s from a list of RawSmsData 864 * records returned by <code>getAllMessagesFromIcc()</code> 865 * 866 * @param records SMS EF records, returned by 867 * <code>getAllMessagesFromIcc</code> 868 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. 869 */ 870 private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { 871 ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); 872 if (records != null) { 873 int count = records.size(); 874 for (int i = 0; i < count; i++) { 875 SmsRawData data = records.get(i); 876 // List contains all records, including "free" records (null) 877 if (data != null) { 878 SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes()); 879 if (sms != null) { 880 messages.add(sms); 881 } 882 } 883 } 884 } 885 return messages; 886 } 887 888 /** 889 * SMS over IMS is supported if IMS is registered and SMS is supported 890 * on IMS. 891 * 892 * @return true if SMS over IMS is supported, false otherwise 893 * 894 * @see #getImsSmsFormat() 895 * 896 * @hide 897 */ 898 boolean isImsSmsSupported() { 899 return isImsSmsSupported(getPreferredSmsSubscription()); 900 } 901 902 /** @hide */ 903 boolean isImsSmsSupported(long subId) { 904 boolean boSupported = false; 905 try { 906 ISms iccISms = getISmsService(); 907 if (iccISms != null) { 908 boSupported = iccISms.isImsSmsSupported(); 909 } 910 } catch (RemoteException ex) { 911 // ignore it 912 } 913 return boSupported; 914 } 915 916 /** 917 * Gets SMS format supported on IMS. SMS over IMS format is 918 * either 3GPP or 3GPP2. 919 * 920 * @return SmsMessage.FORMAT_3GPP, 921 * SmsMessage.FORMAT_3GPP2 922 * or SmsMessage.FORMAT_UNKNOWN 923 * 924 * @see #isImsSmsSupported() 925 * 926 * @hide 927 */ 928 String getImsSmsFormat() { 929 return getImsSmsFormat(getPreferredSmsSubscription()); 930 } 931 932 /** @hide */ 933 String getImsSmsFormat(long subId) { 934 String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN; 935 try { 936 ISms iccISms = getISmsService(); 937 if (iccISms != null) { 938 format = iccISms.getImsSmsFormat(); 939 } 940 } catch (RemoteException ex) { 941 // ignore it 942 } 943 return format; 944 } 945 946 /** 947 * Get the preferred sms subId 948 * 949 * @return the preferred subId 950 * @hide 951 */ 952 public static long getPreferredSmsSubscription() { 953 ISms iccISms = null; 954 try { 955 iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 956 return (long) iccISms.getPreferredSmsSubscription(); 957 } catch (RemoteException ex) { 958 return DEFAULT_SUB; 959 } catch (NullPointerException ex) { 960 return DEFAULT_SUB; 961 } 962 } 963 964 /** 965 * Get SMS prompt property, enabled or not 966 * 967 * @return true if enabled, false otherwise 968 * @hide 969 */ 970 public boolean isSMSPromptEnabled() { 971 ISms iccISms = null; 972 try { 973 iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 974 return iccISms.isSMSPromptEnabled(); 975 } catch (RemoteException ex) { 976 return false; 977 } catch (NullPointerException ex) { 978 return false; 979 } 980 } 981 982 // see SmsMessage.getStatusOnIcc 983 984 /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 985 static public final int STATUS_ON_ICC_FREE = 0; 986 987 /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 988 static public final int STATUS_ON_ICC_READ = 1; 989 990 /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 991 static public final int STATUS_ON_ICC_UNREAD = 3; 992 993 /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 994 static public final int STATUS_ON_ICC_SENT = 5; 995 996 /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 997 static public final int STATUS_ON_ICC_UNSENT = 7; 998 999 // SMS send failure result codes 1000 1001 /** Generic failure cause */ 1002 static public final int RESULT_ERROR_GENERIC_FAILURE = 1; 1003 /** Failed because radio was explicitly turned off */ 1004 static public final int RESULT_ERROR_RADIO_OFF = 2; 1005 /** Failed because no pdu provided */ 1006 static public final int RESULT_ERROR_NULL_PDU = 3; 1007 /** Failed because service is currently unavailable */ 1008 static public final int RESULT_ERROR_NO_SERVICE = 4; 1009 /** Failed because we reached the sending queue limit. {@hide} */ 1010 static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5; 1011 /** Failed because FDN is enabled. {@hide} */ 1012 static public final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; 1013 1014 /** 1015 * Send an MMS message 1016 * 1017 * @param pdu the MMS message encoded in standard MMS PDU format 1018 * @param locationUrl the optional location url where message should be sent to 1019 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1020 * broadcast when the message is successfully sent, or failed 1021 * @hide 1022 */ 1023 public void sendMultimediaMessage(byte[] pdu, String locationUrl, PendingIntent sentIntent) { 1024 if (pdu == null || pdu.length == 0) { 1025 throw new IllegalArgumentException("Empty or zero length PDU"); 1026 } 1027 try { 1028 final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1029 if (iMms == null) { 1030 return; 1031 } 1032 iMms.sendMessage(ActivityThread.currentPackageName(), pdu, locationUrl, sentIntent); 1033 } catch (RemoteException e) { 1034 // Ignore it 1035 } 1036 } 1037 1038 /** 1039 * Download an MMS message from carrier by a given location URL 1040 * 1041 * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained 1042 * from the MMS WAP push notification 1043 * @param downloadedIntent if not NULL this <code>PendingIntent</code> is 1044 * broadcast when the message is downloaded, or the download is failed 1045 * @hide 1046 */ 1047 public void downloadMultimediaMessage(String locationUrl, PendingIntent downloadedIntent) { 1048 if (TextUtils.isEmpty(locationUrl)) { 1049 throw new IllegalArgumentException("Empty MMS location URL"); 1050 } 1051 try { 1052 final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1053 if (iMms == null) { 1054 return; 1055 } 1056 iMms.downloadMessage(ActivityThread.currentPackageName(), locationUrl, 1057 downloadedIntent); 1058 } catch (RemoteException e) { 1059 // Ignore it 1060 } 1061 } 1062 1063 // MMS send/download failure result codes 1064 /**@hide*/ 1065 public static final int MMS_ERROR_UNSPECIFIED = 1; 1066 /**@hide*/ 1067 public static final int MMS_ERROR_INVALID_APN = 2; 1068 /**@hide*/ 1069 public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; 1070 /**@hide*/ 1071 public static final int MMS_ERROR_HTTP_FAILURE = 4; 1072 1073 // Intent extra name for result data 1074 /**@hide*/ 1075 public static final String MMS_EXTRA_DATA = "data"; 1076 1077} 1078