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