SmsManager.java revision e97d1c6a8f95c240b0e990ce73d43e07c3cf413d
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.ActivityNotFoundException; 22import android.content.ContentValues; 23import android.content.Context; 24import android.content.Intent; 25import android.net.Uri; 26import android.os.BaseBundle; 27import android.os.Bundle; 28import android.os.RemoteException; 29import android.os.ServiceManager; 30import android.text.TextUtils; 31import android.util.ArrayMap; 32import android.util.Log; 33 34import com.android.internal.telephony.IMms; 35import com.android.internal.telephony.ISms; 36import com.android.internal.telephony.SmsRawData; 37 38import java.util.ArrayList; 39import java.util.Arrays; 40import java.util.List; 41import java.util.Map; 42 43/* 44 * TODO(code review): Curious question... Why are a lot of these 45 * methods not declared as static, since they do not seem to require 46 * any local object state? Presumably this cannot be changed without 47 * interfering with the API... 48 */ 49 50/** 51 * Manages SMS operations such as sending data, text, and pdu SMS messages. 52 * Get this object by calling the static method {@link #getDefault()}. 53 * 54 * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19) 55 * and higher, see {@link android.provider.Telephony}. 56 */ 57public final class SmsManager { 58 private static final String TAG = "SmsManager"; 59 /** 60 * A psuedo-subId that represents the default subId at any given time. The actual subId it 61 * represents changes as the default subId is changed. 62 */ 63 private static final int DEFAULT_SUBSCRIPTION_ID = -1002; 64 65 /** Singleton object constructed during class initialization. */ 66 private static final SmsManager sInstance = new SmsManager(DEFAULT_SUBSCRIPTION_ID); 67 private static final Object sLockObject = new Object(); 68 69 /** @hide */ 70 public static final int CELL_BROADCAST_RAN_TYPE_GSM = 0; 71 /** @hide */ 72 public static final int CELL_BROADCAST_RAN_TYPE_CDMA = 1; 73 74 /** SMS record length from TS 51.011 10.5.3 75 * @hide 76 */ 77 public static final int SMS_RECORD_LENGTH = 176; 78 79 /** SMS record length from C.S0023 3.4.27 80 * @hide 81 */ 82 public static final int CDMA_SMS_RECORD_LENGTH = 255; 83 84 private static final Map<Integer, SmsManager> sSubInstances = 85 new ArrayMap<Integer, SmsManager>(); 86 87 /** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */ 88 private int mSubId; 89 90 /* 91 * Key for the various carrier-dependent configuration values. 92 * Some of the values are used by the system in processing SMS or MMS messages. Others 93 * are provided for the convenience of SMS applications. 94 */ 95 96 /** 97 * Whether to append transaction id to MMS WAP Push M-Notification.ind's content location URI 98 * when constructing the download URL of a new MMS (boolean type) 99 */ 100 public static final String MMS_CONFIG_APPEND_TRANSACTION_ID = 101 CarrierConfigManager.KEY_MMS_APPEND_TRANSACTION_ID_BOOL; 102 /** 103 * Whether MMS is enabled for the current carrier (boolean type) 104 */ 105 public static final String 106 MMS_CONFIG_MMS_ENABLED = CarrierConfigManager.KEY_MMS_MMS_ENABLED_BOOL; 107 /** 108 * Whether group MMS is enabled for the current carrier (boolean type) 109 */ 110 public static final String 111 MMS_CONFIG_GROUP_MMS_ENABLED = CarrierConfigManager.KEY_MMS_GROUP_MMS_ENABLED_BOOL; 112 /** 113 * If this is enabled, M-NotifyResp.ind should be sent to the WAP Push content location instead 114 * of the default MMSC (boolean type) 115 */ 116 public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED = 117 CarrierConfigManager.KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL; 118 /** 119 * Whether alias is enabled (boolean type) 120 */ 121 public static final String 122 MMS_CONFIG_ALIAS_ENABLED = CarrierConfigManager.KEY_MMS_ALIAS_ENABLED_BOOL; 123 /** 124 * Whether audio is allowed to be attached for MMS messages (boolean type) 125 */ 126 public static final String 127 MMS_CONFIG_ALLOW_ATTACH_AUDIO = CarrierConfigManager.KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL; 128 /** 129 * Whether multipart SMS is enabled (boolean type) 130 */ 131 public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED = 132 CarrierConfigManager.KEY_MMS_MULTIPART_SMS_ENABLED_BOOL; 133 /** 134 * Whether SMS delivery report is enabled (boolean type) 135 */ 136 public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED = 137 CarrierConfigManager.KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL; 138 /** 139 * Whether content-disposition field should be expected in an MMS PDU (boolean type) 140 */ 141 public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION = 142 CarrierConfigManager.KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL; 143 /** 144 * Whether multipart SMS should be sent as separate messages 145 */ 146 public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES = 147 CarrierConfigManager.KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL; 148 /** 149 * Whether MMS read report is enabled (boolean type) 150 */ 151 public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED = 152 CarrierConfigManager.KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL; 153 /** 154 * Whether MMS delivery report is enabled (boolean type) 155 */ 156 public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED = 157 CarrierConfigManager.KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL; 158 /** 159 * Max MMS message size in bytes (int type) 160 */ 161 public static final String 162 MMS_CONFIG_MAX_MESSAGE_SIZE = CarrierConfigManager.KEY_MMS_MAX_MESSAGE_SIZE_INT; 163 /** 164 * Max MMS image width (int type) 165 */ 166 public static final String 167 MMS_CONFIG_MAX_IMAGE_WIDTH = CarrierConfigManager.KEY_MMS_MAX_IMAGE_WIDTH_INT; 168 /** 169 * Max MMS image height (int type) 170 */ 171 public static final String 172 MMS_CONFIG_MAX_IMAGE_HEIGHT = CarrierConfigManager.KEY_MMS_MAX_IMAGE_HEIGHT_INT; 173 /** 174 * Limit of recipients of MMS messages (int type) 175 */ 176 public static final String 177 MMS_CONFIG_RECIPIENT_LIMIT = CarrierConfigManager.KEY_MMS_RECIPIENT_LIMIT_INT; 178 /** 179 * Min alias character count (int type) 180 */ 181 public static final String 182 MMS_CONFIG_ALIAS_MIN_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MIN_CHARS_INT; 183 /** 184 * Max alias character count (int type) 185 */ 186 public static final String 187 MMS_CONFIG_ALIAS_MAX_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MAX_CHARS_INT; 188 /** 189 * When the number of parts of a multipart SMS reaches this threshold, it should be converted 190 * into an MMS (int type) 191 */ 192 public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD = 193 CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT; 194 /** 195 * Some carriers require SMS to be converted into MMS when text length reaches this threshold 196 * (int type) 197 */ 198 public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD = 199 CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT; 200 /** 201 * Max message text size (int type) 202 */ 203 public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE = 204 CarrierConfigManager.KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT; 205 /** 206 * Max message subject length (int type) 207 */ 208 public static final String 209 MMS_CONFIG_SUBJECT_MAX_LENGTH = CarrierConfigManager.KEY_MMS_SUBJECT_MAX_LENGTH_INT; 210 /** 211 * MMS HTTP socket timeout in milliseconds (int type) 212 */ 213 public static final String 214 MMS_CONFIG_HTTP_SOCKET_TIMEOUT = CarrierConfigManager.KEY_MMS_HTTP_SOCKET_TIMEOUT_INT; 215 /** 216 * The name of the UA Prof URL HTTP header for MMS HTTP request (String type) 217 */ 218 public static final String 219 MMS_CONFIG_UA_PROF_TAG_NAME = CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING; 220 /** 221 * The User-Agent header value for MMS HTTP request (String type) 222 */ 223 public static final String 224 MMS_CONFIG_USER_AGENT = CarrierConfigManager.KEY_MMS_USER_AGENT_STRING; 225 /** 226 * The UA Profile URL header value for MMS HTTP request (String type) 227 */ 228 public static final String 229 MMS_CONFIG_UA_PROF_URL = CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING; 230 /** 231 * A list of HTTP headers to add to MMS HTTP request, separated by "|" (String type) 232 */ 233 public static final String 234 MMS_CONFIG_HTTP_PARAMS = CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING; 235 /** 236 * Email gateway number (String type) 237 */ 238 public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER = 239 CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING; 240 /** 241 * The suffix to append to the NAI header value for MMS HTTP request (String type) 242 */ 243 public static final String 244 MMS_CONFIG_NAI_SUFFIX = CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING; 245 /** 246 * If true, show the cell broadcast (amber alert) in the SMS settings. Some carriers don't want 247 * this shown. (Boolean type) 248 */ 249 public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS = 250 CarrierConfigManager.KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL; 251 /** 252 * Whether the carrier MMSC supports charset field in Content-Type header. If this is false, 253 * then we don't add "charset" to "Content-Type" 254 */ 255 public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER = 256 CarrierConfigManager.KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL; 257 /** 258 * If true, add "Connection: close" header to MMS HTTP requests so the connection 259 * is immediately closed (disabling keep-alive). (Boolean type) 260 * @hide 261 */ 262 public static final String MMS_CONFIG_CLOSE_CONNECTION = 263 CarrierConfigManager.KEY_MMS_CLOSE_CONNECTION_BOOL; 264 265 /* 266 * Forwarded constants from SimDialogActivity. 267 */ 268 private static String DIALOG_TYPE_KEY = "dialog_type"; 269 private static final int SMS_PICK = 2; 270 271 /** 272 * Send a text based SMS. 273 * 274 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 275 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 276 * 277 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 278 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 279 * writes messages sent using this method to the SMS Provider (the default SMS app is always 280 * responsible for writing its sent messages to the SMS Provider). For information about 281 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 282 * 283 * 284 * @param destinationAddress the address to send the message to 285 * @param scAddress is the service center address or null to use 286 * the current default SMSC 287 * @param text the body of the message to send 288 * @param sentIntent if not NULL this <code>PendingIntent</code> is 289 * broadcast when the message is successfully sent, or failed. 290 * The result code will be <code>Activity.RESULT_OK</code> for success, 291 * or one of these errors:<br> 292 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 293 * <code>RESULT_ERROR_RADIO_OFF</code><br> 294 * <code>RESULT_ERROR_NULL_PDU</code><br> 295 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 296 * the extra "errorCode" containing a radio technology specific value, 297 * generally only useful for troubleshooting.<br> 298 * The per-application based SMS control checks sentIntent. If sentIntent 299 * is NULL the caller will be checked against all unknown applications, 300 * which cause smaller number of SMS to be sent in checking period. 301 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 302 * broadcast when the message is delivered to the recipient. The 303 * raw pdu of the status report is in the extended data ("pdu"). 304 * 305 * @throws IllegalArgumentException if destinationAddress or text are empty 306 */ 307 public void sendTextMessage( 308 String destinationAddress, String scAddress, String text, 309 PendingIntent sentIntent, PendingIntent deliveryIntent) { 310 sendTextMessageInternal(destinationAddress, scAddress, text, 311 sentIntent, deliveryIntent, true /* persistMessageForCarrierApp*/); 312 } 313 314 private void sendTextMessageInternal(String destinationAddress, String scAddress, 315 String text, PendingIntent sentIntent, PendingIntent deliveryIntent, 316 boolean persistMessageForCarrierApp) { 317 if (TextUtils.isEmpty(destinationAddress)) { 318 throw new IllegalArgumentException("Invalid destinationAddress"); 319 } 320 321 if (TextUtils.isEmpty(text)) { 322 throw new IllegalArgumentException("Invalid message body"); 323 } 324 325 try { 326 ISms iccISms = getISmsServiceOrThrow(); 327 iccISms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(), 328 destinationAddress, 329 scAddress, text, sentIntent, deliveryIntent, 330 persistMessageForCarrierApp); 331 } catch (RemoteException ex) { 332 // ignore it 333 } 334 } 335 336 /** 337 * Send a text based SMS without writing it into the SMS Provider. 338 * 339 * <p>Only the carrier app can call this method.</p> 340 * 341 * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent) 342 * @hide 343 */ 344 public void sendTextMessageWithoutPersisting( 345 String destinationAddress, String scAddress, String text, 346 PendingIntent sentIntent, PendingIntent deliveryIntent) { 347 sendTextMessageInternal(destinationAddress, scAddress, text, 348 sentIntent, deliveryIntent, false /* persistMessageForCarrierApp*/); 349 } 350 351 /** 352 * A variant of {@link SmsManager#sendTextMessage} that allows self to be the caller. This is 353 * for internal use only. 354 * 355 * @param persistMessage whether to persist the sent message in the SMS app. the caller must be 356 * the Phone process if set to false. 357 * 358 * @hide 359 */ 360 public void sendTextMessageWithSelfPermissions( 361 String destinationAddress, String scAddress, String text, 362 PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage) { 363 if (TextUtils.isEmpty(destinationAddress)) { 364 throw new IllegalArgumentException("Invalid destinationAddress"); 365 } 366 367 if (TextUtils.isEmpty(text)) { 368 throw new IllegalArgumentException("Invalid message body"); 369 } 370 371 try { 372 ISms iccISms = getISmsServiceOrThrow(); 373 iccISms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(), 374 ActivityThread.currentPackageName(), 375 destinationAddress, 376 scAddress, text, sentIntent, deliveryIntent, persistMessage); 377 } catch (RemoteException ex) { 378 // ignore it 379 } 380 } 381 382 /** 383 * Inject an SMS PDU into the android application framework. 384 * 385 * The caller should have carrier privileges. 386 * @see android.telephony.TelephonyManager#hasCarrierPrivileges 387 * 388 * @param pdu is the byte array of pdu to be injected into android application framework 389 * @param format is the format of SMS pdu (3gpp or 3gpp2) 390 * @param receivedIntent if not NULL this <code>PendingIntent</code> is 391 * broadcast when the message is successfully received by the 392 * android application framework, or failed. This intent is broadcasted at 393 * the same time an SMS received from radio is acknowledged back. 394 * The result code will be <code>RESULT_SMS_HANDLED</code> for success, or 395 * <code>RESULT_SMS_GENERIC_ERROR</code> for error. 396 * 397 * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2. 398 */ 399 public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) { 400 if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) { 401 // Format must be either 3gpp or 3gpp2. 402 throw new IllegalArgumentException( 403 "Invalid pdu format. format must be either 3gpp or 3gpp2"); 404 } 405 try { 406 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 407 if (iccISms != null) { 408 iccISms.injectSmsPduForSubscriber( 409 getSubscriptionId(), pdu, format, receivedIntent); 410 } 411 } catch (RemoteException ex) { 412 // ignore it 413 } 414 } 415 416 /** 417 * Divide a message text into several fragments, none bigger than 418 * the maximum SMS message size. 419 * 420 * @param text the original message. Must not be null. 421 * @return an <code>ArrayList</code> of strings that, in order, 422 * comprise the original message 423 * 424 * @throws IllegalArgumentException if text is null 425 */ 426 public ArrayList<String> divideMessage(String text) { 427 if (null == text) { 428 throw new IllegalArgumentException("text is null"); 429 } 430 return SmsMessage.fragmentText(text); 431 } 432 433 /** 434 * Send a multi-part text based SMS. The callee should have already 435 * divided the message into correctly sized parts by calling 436 * <code>divideMessage</code>. 437 * 438 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 439 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 440 * 441 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 442 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 443 * writes messages sent using this method to the SMS Provider (the default SMS app is always 444 * responsible for writing its sent messages to the SMS Provider). For information about 445 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 446 * 447 * @param destinationAddress the address to send the message to 448 * @param scAddress is the service center address or null to use 449 * the current default SMSC 450 * @param parts an <code>ArrayList</code> of strings that, in order, 451 * comprise the original message 452 * @param sentIntents if not null, an <code>ArrayList</code> of 453 * <code>PendingIntent</code>s (one for each message part) that is 454 * broadcast when the corresponding message part has been sent. 455 * The result code will be <code>Activity.RESULT_OK</code> for success, 456 * or one of these errors:<br> 457 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 458 * <code>RESULT_ERROR_RADIO_OFF</code><br> 459 * <code>RESULT_ERROR_NULL_PDU</code><br> 460 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 461 * the extra "errorCode" containing a radio technology specific value, 462 * generally only useful for troubleshooting.<br> 463 * The per-application based SMS control checks sentIntent. If sentIntent 464 * is NULL the caller will be checked against all unknown applications, 465 * which cause smaller number of SMS to be sent in checking period. 466 * @param deliveryIntents if not null, an <code>ArrayList</code> of 467 * <code>PendingIntent</code>s (one for each message part) that is 468 * broadcast when the corresponding message part has been delivered 469 * to the recipient. The raw pdu of the status report is in the 470 * extended data ("pdu"). 471 * 472 * @throws IllegalArgumentException if destinationAddress or data are empty 473 */ 474 public void sendMultipartTextMessage( 475 String destinationAddress, String scAddress, ArrayList<String> parts, 476 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 477 sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, 478 sentIntents, deliveryIntents, true /* persistMessageForCarrierApp*/); 479 } 480 481 private void sendMultipartTextMessageInternal( 482 String destinationAddress, String scAddress, ArrayList<String> parts, 483 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, 484 boolean persistMessageForCarrierApp) { 485 if (TextUtils.isEmpty(destinationAddress)) { 486 throw new IllegalArgumentException("Invalid destinationAddress"); 487 } 488 if (parts == null || parts.size() < 1) { 489 throw new IllegalArgumentException("Invalid message body"); 490 } 491 492 if (parts.size() > 1) { 493 try { 494 ISms iccISms = getISmsServiceOrThrow(); 495 iccISms.sendMultipartTextForSubscriber(getSubscriptionId(), 496 ActivityThread.currentPackageName(), 497 destinationAddress, scAddress, parts, 498 sentIntents, deliveryIntents, persistMessageForCarrierApp); 499 } catch (RemoteException ex) { 500 // ignore it 501 } 502 } else { 503 PendingIntent sentIntent = null; 504 PendingIntent deliveryIntent = null; 505 if (sentIntents != null && sentIntents.size() > 0) { 506 sentIntent = sentIntents.get(0); 507 } 508 if (deliveryIntents != null && deliveryIntents.size() > 0) { 509 deliveryIntent = deliveryIntents.get(0); 510 } 511 sendTextMessage(destinationAddress, scAddress, parts.get(0), 512 sentIntent, deliveryIntent); 513 } 514 } 515 516 /** 517 * Send a multi-part text based SMS without writing it into the SMS Provider. 518 * 519 * <p>Only the carrier app can call this method.</p> 520 * 521 * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList) 522 * @hide 523 **/ 524 public void sendMultipartTextMessageWithoutPersisting( 525 String destinationAddress, String scAddress, ArrayList<String> parts, 526 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 527 sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, 528 sentIntents, deliveryIntents, false /* persistMessageForCarrierApp*/); 529 } 530 531 /** 532 * Send a data based SMS to a specific application port. 533 * 534 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 535 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 536 * 537 * @param destinationAddress the address to send the message to 538 * @param scAddress is the service center address or null to use 539 * the current default SMSC 540 * @param destinationPort the port to deliver the message to 541 * @param data the body of the message to send 542 * @param sentIntent if not NULL this <code>PendingIntent</code> is 543 * broadcast when the message is successfully sent, or failed. 544 * The result code will be <code>Activity.RESULT_OK</code> for success, 545 * or one of these errors:<br> 546 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 547 * <code>RESULT_ERROR_RADIO_OFF</code><br> 548 * <code>RESULT_ERROR_NULL_PDU</code><br> 549 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 550 * the extra "errorCode" containing a radio technology specific value, 551 * generally only useful for troubleshooting.<br> 552 * The per-application based SMS control checks sentIntent. If sentIntent 553 * is NULL the caller will be checked against all unknown applications, 554 * which cause smaller number of SMS to be sent in checking period. 555 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 556 * broadcast when the message is delivered to the recipient. The 557 * raw pdu of the status report is in the extended data ("pdu"). 558 * 559 * @throws IllegalArgumentException if destinationAddress or data are empty 560 */ 561 public void sendDataMessage( 562 String destinationAddress, String scAddress, short destinationPort, 563 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 564 if (TextUtils.isEmpty(destinationAddress)) { 565 throw new IllegalArgumentException("Invalid destinationAddress"); 566 } 567 568 if (data == null || data.length == 0) { 569 throw new IllegalArgumentException("Invalid message data"); 570 } 571 572 try { 573 ISms iccISms = getISmsServiceOrThrow(); 574 iccISms.sendDataForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(), 575 destinationAddress, scAddress, destinationPort & 0xFFFF, 576 data, sentIntent, deliveryIntent); 577 } catch (RemoteException ex) { 578 // ignore it 579 } 580 } 581 582 /** 583 * A variant of {@link SmsManager#sendDataMessage} that allows self to be the caller. This is 584 * for internal use only. 585 * 586 * @hide 587 */ 588 public void sendDataMessageWithSelfPermissions( 589 String destinationAddress, String scAddress, short destinationPort, 590 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 591 if (TextUtils.isEmpty(destinationAddress)) { 592 throw new IllegalArgumentException("Invalid destinationAddress"); 593 } 594 595 if (data == null || data.length == 0) { 596 throw new IllegalArgumentException("Invalid message data"); 597 } 598 599 try { 600 ISms iccISms = getISmsServiceOrThrow(); 601 iccISms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(), 602 ActivityThread.currentPackageName(), destinationAddress, scAddress, 603 destinationPort & 0xFFFF, data, sentIntent, deliveryIntent); 604 } catch (RemoteException ex) { 605 // ignore it 606 } 607 } 608 609 610 611 /** 612 * Get the SmsManager associated with the default subscription id. The instance will always be 613 * associated with the default subscription id, even if the default subscription id is changed. 614 * 615 * @return the SmsManager associated with the default subscription id 616 */ 617 public static SmsManager getDefault() { 618 return sInstance; 619 } 620 621 /** 622 * Get the the instance of the SmsManager associated with a particular subscription id 623 * 624 * @param subId an SMS subscription id, typically accessed using 625 * {@link android.telephony.SubscriptionManager} 626 * @return the instance of the SmsManager associated with subId 627 */ 628 public static SmsManager getSmsManagerForSubscriptionId(int subId) { 629 // TODO(shri): Add javadoc link once SubscriptionManager is made public api 630 synchronized(sLockObject) { 631 SmsManager smsManager = sSubInstances.get(subId); 632 if (smsManager == null) { 633 smsManager = new SmsManager(subId); 634 sSubInstances.put(subId, smsManager); 635 } 636 return smsManager; 637 } 638 } 639 640 private SmsManager(int subId) { 641 mSubId = subId; 642 } 643 644 /** 645 * Get the associated subscription id. If the instance was returned by {@link #getDefault()}, 646 * then this method may return different values at different points in time (if the user 647 * changes the default subscription id). It will return < 0 if the default subscription id 648 * cannot be determined. 649 * 650 * Additionally, to support legacy applications that are not multi-SIM aware, 651 * if the following are true: 652 * - We are using a multi-SIM device 653 * - A default SMS SIM has not been selected 654 * - At least one SIM subscription is available 655 * then ask the user to set the default SMS SIM. 656 * 657 * @return associated subscription id 658 */ 659 public int getSubscriptionId() { 660 final int subId = (mSubId == DEFAULT_SUBSCRIPTION_ID) 661 ? getDefaultSmsSubscriptionId() : mSubId; 662 boolean isSmsSimPickActivityNeeded = false; 663 final Context context = ActivityThread.currentApplication().getApplicationContext(); 664 try { 665 ISms iccISms = getISmsService(); 666 if (iccISms != null) { 667 isSmsSimPickActivityNeeded = iccISms.isSmsSimPickActivityNeeded(subId); 668 } 669 } catch (RemoteException ex) { 670 Log.e(TAG, "Exception in getSubscriptionId"); 671 } 672 673 if (isSmsSimPickActivityNeeded) { 674 Log.d(TAG, "getSubscriptionId isSmsSimPickActivityNeeded is true"); 675 // ask the user for a default SMS SIM. 676 Intent intent = new Intent(); 677 intent.setClassName("com.android.settings", 678 "com.android.settings.sim.SimDialogActivity"); 679 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 680 intent.putExtra(DIALOG_TYPE_KEY, SMS_PICK); 681 try { 682 context.startActivity(intent); 683 } catch (ActivityNotFoundException anfe) { 684 // If Settings is not installed, only log the error as we do not want to break 685 // legacy applications. 686 Log.e(TAG, "Unable to launch Settings application."); 687 } 688 } 689 690 return subId; 691 } 692 693 /** 694 * Returns the ISms service, or throws an UnsupportedOperationException if 695 * the service does not exist. 696 */ 697 private static ISms getISmsServiceOrThrow() { 698 ISms iccISms = getISmsService(); 699 if (iccISms == null) { 700 throw new UnsupportedOperationException("Sms is not supported"); 701 } 702 return iccISms; 703 } 704 705 private static ISms getISmsService() { 706 return ISms.Stub.asInterface(ServiceManager.getService("isms")); 707 } 708 709 /** 710 * Copy a raw SMS PDU to the ICC. 711 * ICC (Integrated Circuit Card) is the card of the device. 712 * For example, this can be the SIM or USIM for GSM. 713 * 714 * @param smsc the SMSC for this message, or NULL for the default SMSC 715 * @param pdu the raw PDU to store 716 * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, 717 * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) 718 * @return true for success 719 * 720 * @throws IllegalArgumentException if pdu is NULL 721 * {@hide} 722 */ 723 public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) { 724 boolean success = false; 725 726 if (null == pdu) { 727 throw new IllegalArgumentException("pdu is NULL"); 728 } 729 try { 730 ISms iccISms = getISmsService(); 731 if (iccISms != null) { 732 success = iccISms.copyMessageToIccEfForSubscriber(getSubscriptionId(), 733 ActivityThread.currentPackageName(), 734 status, pdu, smsc); 735 } 736 } catch (RemoteException ex) { 737 // ignore it 738 } 739 740 return success; 741 } 742 743 /** 744 * Delete the specified message from the ICC. 745 * ICC (Integrated Circuit Card) is the card of the device. 746 * For example, this can be the SIM or USIM for GSM. 747 * 748 * @param messageIndex is the record index of the message on ICC 749 * @return true for success 750 * 751 * {@hide} 752 */ 753 public boolean 754 deleteMessageFromIcc(int messageIndex) { 755 boolean success = false; 756 byte[] pdu = new byte[SMS_RECORD_LENGTH-1]; 757 Arrays.fill(pdu, (byte)0xff); 758 759 try { 760 ISms iccISms = getISmsService(); 761 if (iccISms != null) { 762 success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(), 763 ActivityThread.currentPackageName(), 764 messageIndex, STATUS_ON_ICC_FREE, pdu); 765 } 766 } catch (RemoteException ex) { 767 // ignore it 768 } 769 770 return success; 771 } 772 773 /** 774 * Update the specified message on the ICC. 775 * ICC (Integrated Circuit Card) is the card of the device. 776 * For example, this can be the SIM or USIM for GSM. 777 * 778 * @param messageIndex record index of message to update 779 * @param newStatus new message status (STATUS_ON_ICC_READ, 780 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 781 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 782 * @param pdu the raw PDU to store 783 * @return true for success 784 * 785 * {@hide} 786 */ 787 public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { 788 boolean success = false; 789 790 try { 791 ISms iccISms = getISmsService(); 792 if (iccISms != null) { 793 success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(), 794 ActivityThread.currentPackageName(), 795 messageIndex, newStatus, pdu); 796 } 797 } catch (RemoteException ex) { 798 // ignore it 799 } 800 801 return success; 802 } 803 804 /** 805 * Retrieves all messages currently stored on ICC. 806 * ICC (Integrated Circuit Card) is the card of the device. 807 * For example, this can be the SIM or USIM for GSM. 808 * 809 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects 810 * 811 * {@hide} 812 */ 813 public ArrayList<SmsMessage> getAllMessagesFromIcc() { 814 List<SmsRawData> records = null; 815 816 try { 817 ISms iccISms = getISmsService(); 818 if (iccISms != null) { 819 records = iccISms.getAllMessagesFromIccEfForSubscriber( 820 getSubscriptionId(), 821 ActivityThread.currentPackageName()); 822 } 823 } catch (RemoteException ex) { 824 // ignore it 825 } 826 827 return createMessageListFromRawRecords(records); 828 } 829 830 /** 831 * Enable reception of cell broadcast (SMS-CB) messages with the given 832 * message identifier and RAN type. The RAN type specify this message ID 833 * belong to 3GPP (GSM) or 3GPP2(CDMA).Note that if two different clients 834 * enable the same message identifier, they must both disable it for the device to stop 835 * receiving those messages. All received messages will be broadcast in an 836 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 837 * Note: This call is blocking, callers may want to avoid calling it from 838 * the main thread of an application. 839 * 840 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 841 * or C.R1001-G (3GPP2) 842 * @param ranType as defined in class SmsManager, the value can be one of these: 843 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM 844 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA 845 * @return true if successful, false otherwise 846 * @see #disableCellBroadcast(int, int) 847 * 848 * {@hide} 849 */ 850 public boolean enableCellBroadcast(int messageIdentifier, int ranType) { 851 boolean success = false; 852 853 try { 854 ISms iccISms = getISmsService(); 855 if (iccISms != null) { 856 success = iccISms.enableCellBroadcastForSubscriber( 857 getSubscriptionId(), messageIdentifier, ranType); 858 } 859 } catch (RemoteException ex) { 860 // ignore it 861 } 862 863 return success; 864 } 865 866 /** 867 * Disable reception of cell broadcast (SMS-CB) messages with the given 868 * message identifier and RAN type. The RAN type specify this message ID 869 * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients 870 * enable the same message identifier, they must both disable it for the 871 * device to stop receiving those messages. 872 * Note: This call is blocking, callers may want to avoid calling it from 873 * the main thread of an application. 874 * 875 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 876 * or C.R1001-G (3GPP2) 877 * @param ranType as defined in class SmsManager, the value can be one of these: 878 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM 879 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA 880 * @return true if successful, false otherwise 881 * 882 * @see #enableCellBroadcast(int, int) 883 * 884 * {@hide} 885 */ 886 public boolean disableCellBroadcast(int messageIdentifier, int ranType) { 887 boolean success = false; 888 889 try { 890 ISms iccISms = getISmsService(); 891 if (iccISms != null) { 892 success = iccISms.disableCellBroadcastForSubscriber( 893 getSubscriptionId(), messageIdentifier, ranType); 894 } 895 } catch (RemoteException ex) { 896 // ignore it 897 } 898 899 return success; 900 } 901 902 /** 903 * Enable reception of cell broadcast (SMS-CB) messages with the given 904 * message identifier range and RAN type. The RAN type specify this message ID 905 * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable 906 * the same message identifier, they must both disable it for the device to stop 907 * receiving those messages. All received messages will be broadcast in an 908 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 909 * Note: This call is blocking, callers may want to avoid calling it from 910 * the main thread of an application. 911 * 912 * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) 913 * or C.R1001-G (3GPP2) 914 * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) 915 * or C.R1001-G (3GPP2) 916 * @param ranType as defined in class SmsManager, the value can be one of these: 917 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM 918 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA 919 * @return true if successful, false otherwise 920 * @see #disableCellBroadcastRange(int, int, int) 921 * 922 * @throws IllegalArgumentException if endMessageId < startMessageId 923 * {@hide} 924 */ 925 public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) { 926 boolean success = false; 927 928 if (endMessageId < startMessageId) { 929 throw new IllegalArgumentException("endMessageId < startMessageId"); 930 } 931 try { 932 ISms iccISms = getISmsService(); 933 if (iccISms != null) { 934 success = iccISms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(), 935 startMessageId, endMessageId, ranType); 936 } 937 } catch (RemoteException ex) { 938 // ignore it 939 } 940 941 return success; 942 } 943 944 /** 945 * Disable reception of cell broadcast (SMS-CB) messages with the given 946 * message identifier range and RAN type. The RAN type specify this message 947 * ID range belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different 948 * clients enable the same message identifier, they must both disable it for 949 * the device to stop receiving those messages. 950 * Note: This call is blocking, callers may want to avoid calling it from 951 * the main thread of an application. 952 * 953 * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) 954 * or C.R1001-G (3GPP2) 955 * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) 956 * or C.R1001-G (3GPP2) 957 * @param ranType as defined in class SmsManager, the value can be one of these: 958 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM 959 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA 960 * @return true if successful, false otherwise 961 * 962 * @see #enableCellBroadcastRange(int, int, int) 963 * 964 * @throws IllegalArgumentException if endMessageId < startMessageId 965 * {@hide} 966 */ 967 public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) { 968 boolean success = false; 969 970 if (endMessageId < startMessageId) { 971 throw new IllegalArgumentException("endMessageId < startMessageId"); 972 } 973 try { 974 ISms iccISms = getISmsService(); 975 if (iccISms != null) { 976 success = iccISms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(), 977 startMessageId, endMessageId, ranType); 978 } 979 } catch (RemoteException ex) { 980 // ignore it 981 } 982 983 return success; 984 } 985 986 /** 987 * Create a list of <code>SmsMessage</code>s from a list of RawSmsData 988 * records returned by <code>getAllMessagesFromIcc()</code> 989 * 990 * @param records SMS EF records, returned by 991 * <code>getAllMessagesFromIcc</code> 992 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. 993 */ 994 private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { 995 ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); 996 if (records != null) { 997 int count = records.size(); 998 for (int i = 0; i < count; i++) { 999 SmsRawData data = records.get(i); 1000 // List contains all records, including "free" records (null) 1001 if (data != null) { 1002 SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes()); 1003 if (sms != null) { 1004 messages.add(sms); 1005 } 1006 } 1007 } 1008 } 1009 return messages; 1010 } 1011 1012 /** 1013 * SMS over IMS is supported if IMS is registered and SMS is supported 1014 * on IMS. 1015 * 1016 * @return true if SMS over IMS is supported, false otherwise 1017 * 1018 * @see #getImsSmsFormat() 1019 * 1020 * @hide 1021 */ 1022 public boolean isImsSmsSupported() { 1023 boolean boSupported = false; 1024 try { 1025 ISms iccISms = getISmsService(); 1026 if (iccISms != null) { 1027 boSupported = iccISms.isImsSmsSupportedForSubscriber(getSubscriptionId()); 1028 } 1029 } catch (RemoteException ex) { 1030 // ignore it 1031 } 1032 return boSupported; 1033 } 1034 1035 /** 1036 * Gets SMS format supported on IMS. SMS over IMS format is 1037 * either 3GPP or 3GPP2. 1038 * 1039 * @return SmsMessage.FORMAT_3GPP, 1040 * SmsMessage.FORMAT_3GPP2 1041 * or SmsMessage.FORMAT_UNKNOWN 1042 * 1043 * @see #isImsSmsSupported() 1044 * 1045 * @hide 1046 */ 1047 public String getImsSmsFormat() { 1048 String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN; 1049 try { 1050 ISms iccISms = getISmsService(); 1051 if (iccISms != null) { 1052 format = iccISms.getImsSmsFormatForSubscriber(getSubscriptionId()); 1053 } 1054 } catch (RemoteException ex) { 1055 // ignore it 1056 } 1057 return format; 1058 } 1059 1060 /** 1061 * Get default sms subscription id 1062 * 1063 * @return the default SMS subscription id 1064 */ 1065 public static int getDefaultSmsSubscriptionId() { 1066 ISms iccISms = null; 1067 try { 1068 iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 1069 return iccISms.getPreferredSmsSubscription(); 1070 } catch (RemoteException ex) { 1071 return -1; 1072 } catch (NullPointerException ex) { 1073 return -1; 1074 } 1075 } 1076 1077 /** 1078 * Get SMS prompt property, enabled or not 1079 * 1080 * @return true if enabled, false otherwise 1081 * @hide 1082 */ 1083 public boolean isSMSPromptEnabled() { 1084 ISms iccISms = null; 1085 try { 1086 iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 1087 return iccISms.isSMSPromptEnabled(); 1088 } catch (RemoteException ex) { 1089 return false; 1090 } catch (NullPointerException ex) { 1091 return false; 1092 } 1093 } 1094 1095 // see SmsMessage.getStatusOnIcc 1096 1097 /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 1098 static public final int STATUS_ON_ICC_FREE = 0; 1099 1100 /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 1101 static public final int STATUS_ON_ICC_READ = 1; 1102 1103 /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 1104 static public final int STATUS_ON_ICC_UNREAD = 3; 1105 1106 /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 1107 static public final int STATUS_ON_ICC_SENT = 5; 1108 1109 /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 1110 static public final int STATUS_ON_ICC_UNSENT = 7; 1111 1112 // SMS send failure result codes 1113 1114 /** Generic failure cause */ 1115 static public final int RESULT_ERROR_GENERIC_FAILURE = 1; 1116 /** Failed because radio was explicitly turned off */ 1117 static public final int RESULT_ERROR_RADIO_OFF = 2; 1118 /** Failed because no pdu provided */ 1119 static public final int RESULT_ERROR_NULL_PDU = 3; 1120 /** Failed because service is currently unavailable */ 1121 static public final int RESULT_ERROR_NO_SERVICE = 4; 1122 /** Failed because we reached the sending queue limit. {@hide} */ 1123 static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5; 1124 /** Failed because FDN is enabled. {@hide} */ 1125 static public final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; 1126 1127 static private final String PHONE_PACKAGE_NAME = "com.android.phone"; 1128 1129 /** 1130 * Send an MMS message 1131 * 1132 * @param context application context 1133 * @param contentUri the content Uri from which the message pdu will be read 1134 * @param locationUrl the optional location url where message should be sent to 1135 * @param configOverrides the carrier-specific messaging configuration values to override for 1136 * sending the message. 1137 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1138 * broadcast when the message is successfully sent, or failed 1139 * @throws IllegalArgumentException if contentUri is empty 1140 */ 1141 public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, 1142 Bundle configOverrides, PendingIntent sentIntent) { 1143 if (contentUri == null) { 1144 throw new IllegalArgumentException("Uri contentUri null"); 1145 } 1146 try { 1147 final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1148 if (iMms == null) { 1149 return; 1150 } 1151 1152 iMms.sendMessage(getSubscriptionId(), ActivityThread.currentPackageName(), contentUri, 1153 locationUrl, configOverrides, sentIntent); 1154 } catch (RemoteException e) { 1155 // Ignore it 1156 } 1157 } 1158 1159 /** 1160 * Download an MMS message from carrier by a given location URL 1161 * 1162 * @param context application context 1163 * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained 1164 * from the MMS WAP push notification 1165 * @param contentUri the content uri to which the downloaded pdu will be written 1166 * @param configOverrides the carrier-specific messaging configuration values to override for 1167 * downloading the message. 1168 * @param downloadedIntent if not NULL this <code>PendingIntent</code> is 1169 * broadcast when the message is downloaded, or the download is failed 1170 * @throws IllegalArgumentException if locationUrl or contentUri is empty 1171 */ 1172 public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, 1173 Bundle configOverrides, PendingIntent downloadedIntent) { 1174 if (TextUtils.isEmpty(locationUrl)) { 1175 throw new IllegalArgumentException("Empty MMS location URL"); 1176 } 1177 if (contentUri == null) { 1178 throw new IllegalArgumentException("Uri contentUri null"); 1179 } 1180 try { 1181 final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1182 if (iMms == null) { 1183 return; 1184 } 1185 iMms.downloadMessage( 1186 getSubscriptionId(), ActivityThread.currentPackageName(), locationUrl, 1187 contentUri, configOverrides, downloadedIntent); 1188 } catch (RemoteException e) { 1189 // Ignore it 1190 } 1191 } 1192 1193 // MMS send/download failure result codes 1194 public static final int MMS_ERROR_UNSPECIFIED = 1; 1195 public static final int MMS_ERROR_INVALID_APN = 2; 1196 public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; 1197 public static final int MMS_ERROR_HTTP_FAILURE = 4; 1198 public static final int MMS_ERROR_IO_ERROR = 5; 1199 public static final int MMS_ERROR_RETRY = 6; 1200 public static final int MMS_ERROR_CONFIGURATION_ERROR = 7; 1201 public static final int MMS_ERROR_NO_DATA_NETWORK = 8; 1202 1203 /** Intent extra name for MMS sending result data in byte array type */ 1204 public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA"; 1205 /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */ 1206 public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS"; 1207 1208 /** 1209 * Import a text message into system's SMS store 1210 * 1211 * Only default SMS apps can import SMS 1212 * 1213 * @param address the destination(source) address of the sent(received) message 1214 * @param type the type of the message 1215 * @param text the message text 1216 * @param timestampMillis the message timestamp in milliseconds 1217 * @param seen if the message is seen 1218 * @param read if the message is read 1219 * @return the message URI, null if failed 1220 * @hide 1221 */ 1222 public Uri importTextMessage(String address, int type, String text, long timestampMillis, 1223 boolean seen, boolean read) { 1224 try { 1225 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1226 if (iMms != null) { 1227 return iMms.importTextMessage(ActivityThread.currentPackageName(), 1228 address, type, text, timestampMillis, seen, read); 1229 } 1230 } catch (RemoteException ex) { 1231 // ignore it 1232 } 1233 return null; 1234 } 1235 1236 /** Represents the received SMS message for importing {@hide} */ 1237 public static final int SMS_TYPE_INCOMING = 0; 1238 /** Represents the sent SMS message for importing {@hide} */ 1239 public static final int SMS_TYPE_OUTGOING = 1; 1240 1241 /** 1242 * Import a multimedia message into system's MMS store. Only the following PDU type is 1243 * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind 1244 * 1245 * Only default SMS apps can import MMS 1246 * 1247 * @param contentUri the content uri from which to read the PDU of the message to import 1248 * @param messageId the optional message id. Use null if not specifying 1249 * @param timestampSecs the optional message timestamp. Use -1 if not specifying 1250 * @param seen if the message is seen 1251 * @param read if the message is read 1252 * @return the message URI, null if failed 1253 * @throws IllegalArgumentException if pdu is empty 1254 * {@hide} 1255 */ 1256 public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs, 1257 boolean seen, boolean read) { 1258 if (contentUri == null) { 1259 throw new IllegalArgumentException("Uri contentUri null"); 1260 } 1261 try { 1262 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1263 if (iMms != null) { 1264 return iMms.importMultimediaMessage(ActivityThread.currentPackageName(), 1265 contentUri, messageId, timestampSecs, seen, read); 1266 } 1267 } catch (RemoteException ex) { 1268 // ignore it 1269 } 1270 return null; 1271 } 1272 1273 /** 1274 * Delete a system stored SMS or MMS message 1275 * 1276 * Only default SMS apps can delete system stored SMS and MMS messages 1277 * 1278 * @param messageUri the URI of the stored message 1279 * @return true if deletion is successful, false otherwise 1280 * @throws IllegalArgumentException if messageUri is empty 1281 * {@hide} 1282 */ 1283 public boolean deleteStoredMessage(Uri messageUri) { 1284 if (messageUri == null) { 1285 throw new IllegalArgumentException("Empty message URI"); 1286 } 1287 try { 1288 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1289 if (iMms != null) { 1290 return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri); 1291 } 1292 } catch (RemoteException ex) { 1293 // ignore it 1294 } 1295 return false; 1296 } 1297 1298 /** 1299 * Delete a system stored SMS or MMS thread 1300 * 1301 * Only default SMS apps can delete system stored SMS and MMS conversations 1302 * 1303 * @param conversationId the ID of the message conversation 1304 * @return true if deletion is successful, false otherwise 1305 * {@hide} 1306 */ 1307 public boolean deleteStoredConversation(long conversationId) { 1308 try { 1309 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1310 if (iMms != null) { 1311 return iMms.deleteStoredConversation( 1312 ActivityThread.currentPackageName(), conversationId); 1313 } 1314 } catch (RemoteException ex) { 1315 // ignore it 1316 } 1317 return false; 1318 } 1319 1320 /** 1321 * Update the status properties of a system stored SMS or MMS message, e.g. 1322 * the read status of a message, etc. 1323 * 1324 * @param messageUri the URI of the stored message 1325 * @param statusValues a list of status properties in key-value pairs to update 1326 * @return true if update is successful, false otherwise 1327 * @throws IllegalArgumentException if messageUri is empty 1328 * {@hide} 1329 */ 1330 public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) { 1331 if (messageUri == null) { 1332 throw new IllegalArgumentException("Empty message URI"); 1333 } 1334 try { 1335 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1336 if (iMms != null) { 1337 return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(), 1338 messageUri, statusValues); 1339 } 1340 } catch (RemoteException ex) { 1341 // ignore it 1342 } 1343 return false; 1344 } 1345 1346 /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */ 1347 public static final String MESSAGE_STATUS_SEEN = "seen"; 1348 /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */ 1349 public static final String MESSAGE_STATUS_READ = "read"; 1350 1351 /** 1352 * Archive or unarchive a stored conversation 1353 * 1354 * @param conversationId the ID of the message conversation 1355 * @param archived true to archive the conversation, false to unarchive 1356 * @return true if update is successful, false otherwise 1357 * {@hide} 1358 */ 1359 public boolean archiveStoredConversation(long conversationId, boolean archived) { 1360 try { 1361 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1362 if (iMms != null) { 1363 return iMms.archiveStoredConversation(ActivityThread.currentPackageName(), 1364 conversationId, archived); 1365 } 1366 } catch (RemoteException ex) { 1367 // ignore it 1368 } 1369 return false; 1370 } 1371 1372 /** 1373 * Add a text message draft to system SMS store 1374 * 1375 * Only default SMS apps can add SMS draft 1376 * 1377 * @param address the destination address of message 1378 * @param text the body of the message to send 1379 * @return the URI of the stored draft message 1380 * {@hide} 1381 */ 1382 public Uri addTextMessageDraft(String address, String text) { 1383 try { 1384 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1385 if (iMms != null) { 1386 return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text); 1387 } 1388 } catch (RemoteException ex) { 1389 // ignore it 1390 } 1391 return null; 1392 } 1393 1394 /** 1395 * Add a multimedia message draft to system MMS store 1396 * 1397 * Only default SMS apps can add MMS draft 1398 * 1399 * @param contentUri the content uri from which to read the PDU data of the draft MMS 1400 * @return the URI of the stored draft message 1401 * @throws IllegalArgumentException if pdu is empty 1402 * {@hide} 1403 */ 1404 public Uri addMultimediaMessageDraft(Uri contentUri) { 1405 if (contentUri == null) { 1406 throw new IllegalArgumentException("Uri contentUri null"); 1407 } 1408 try { 1409 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1410 if (iMms != null) { 1411 return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(), 1412 contentUri); 1413 } 1414 } catch (RemoteException ex) { 1415 // ignore it 1416 } 1417 return null; 1418 } 1419 1420 /** 1421 * Send a system stored text message. 1422 * 1423 * You can only send a failed text message or a draft text message. 1424 * 1425 * @param messageUri the URI of the stored message 1426 * @param scAddress is the service center address or null to use the current default SMSC 1427 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1428 * broadcast when the message is successfully sent, or failed. 1429 * The result code will be <code>Activity.RESULT_OK</code> for success, 1430 * or one of these errors:<br> 1431 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 1432 * <code>RESULT_ERROR_RADIO_OFF</code><br> 1433 * <code>RESULT_ERROR_NULL_PDU</code><br> 1434 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 1435 * the extra "errorCode" containing a radio technology specific value, 1436 * generally only useful for troubleshooting.<br> 1437 * The per-application based SMS control checks sentIntent. If sentIntent 1438 * is NULL the caller will be checked against all unknown applications, 1439 * which cause smaller number of SMS to be sent in checking period. 1440 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1441 * broadcast when the message is delivered to the recipient. The 1442 * raw pdu of the status report is in the extended data ("pdu"). 1443 * 1444 * @throws IllegalArgumentException if messageUri is empty 1445 * {@hide} 1446 */ 1447 public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent, 1448 PendingIntent deliveryIntent) { 1449 if (messageUri == null) { 1450 throw new IllegalArgumentException("Empty message URI"); 1451 } 1452 try { 1453 ISms iccISms = getISmsServiceOrThrow(); 1454 iccISms.sendStoredText( 1455 getSubscriptionId(), ActivityThread.currentPackageName(), messageUri, 1456 scAddress, sentIntent, deliveryIntent); 1457 } catch (RemoteException ex) { 1458 // ignore it 1459 } 1460 } 1461 1462 /** 1463 * Send a system stored multi-part text message. 1464 * 1465 * You can only send a failed text message or a draft text message. 1466 * The provided <code>PendingIntent</code> lists should match the part number of the 1467 * divided text of the stored message by using <code>divideMessage</code> 1468 * 1469 * @param messageUri the URI of the stored message 1470 * @param scAddress is the service center address or null to use 1471 * the current default SMSC 1472 * @param sentIntents if not null, an <code>ArrayList</code> of 1473 * <code>PendingIntent</code>s (one for each message part) that is 1474 * broadcast when the corresponding message part has been sent. 1475 * The result code will be <code>Activity.RESULT_OK</code> for success, 1476 * or one of these errors:<br> 1477 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 1478 * <code>RESULT_ERROR_RADIO_OFF</code><br> 1479 * <code>RESULT_ERROR_NULL_PDU</code><br> 1480 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 1481 * the extra "errorCode" containing a radio technology specific value, 1482 * generally only useful for troubleshooting.<br> 1483 * The per-application based SMS control checks sentIntent. If sentIntent 1484 * is NULL the caller will be checked against all unknown applications, 1485 * which cause smaller number of SMS to be sent in checking period. 1486 * @param deliveryIntents if not null, an <code>ArrayList</code> of 1487 * <code>PendingIntent</code>s (one for each message part) that is 1488 * broadcast when the corresponding message part has been delivered 1489 * to the recipient. The raw pdu of the status report is in the 1490 * extended data ("pdu"). 1491 * 1492 * @throws IllegalArgumentException if messageUri is empty 1493 * {@hide} 1494 */ 1495 public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress, 1496 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 1497 if (messageUri == null) { 1498 throw new IllegalArgumentException("Empty message URI"); 1499 } 1500 try { 1501 ISms iccISms = getISmsServiceOrThrow(); 1502 iccISms.sendStoredMultipartText( 1503 getSubscriptionId(), ActivityThread.currentPackageName(), messageUri, 1504 scAddress, sentIntents, deliveryIntents); 1505 } catch (RemoteException ex) { 1506 // ignore it 1507 } 1508 } 1509 1510 /** 1511 * Send a system stored MMS message 1512 * 1513 * This is used for sending a previously sent, but failed-to-send, message or 1514 * for sending a text message that has been stored as a draft. 1515 * 1516 * @param messageUri the URI of the stored message 1517 * @param configOverrides the carrier-specific messaging configuration values to override for 1518 * sending the message. 1519 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1520 * broadcast when the message is successfully sent, or failed 1521 * @throws IllegalArgumentException if messageUri is empty 1522 * {@hide} 1523 */ 1524 public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides, 1525 PendingIntent sentIntent) { 1526 if (messageUri == null) { 1527 throw new IllegalArgumentException("Empty message URI"); 1528 } 1529 try { 1530 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1531 if (iMms != null) { 1532 iMms.sendStoredMessage( 1533 getSubscriptionId(), ActivityThread.currentPackageName(), messageUri, 1534 configOverrides, sentIntent); 1535 } 1536 } catch (RemoteException ex) { 1537 // ignore it 1538 } 1539 } 1540 1541 /** 1542 * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system 1543 * 1544 * When this flag is on, all SMS/MMS sent/received are stored by system automatically 1545 * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system 1546 * automatically 1547 * 1548 * This flag can only be changed by default SMS apps 1549 * 1550 * @param enabled Whether to enable message auto persisting 1551 * {@hide} 1552 */ 1553 public void setAutoPersisting(boolean enabled) { 1554 try { 1555 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1556 if (iMms != null) { 1557 iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled); 1558 } 1559 } catch (RemoteException ex) { 1560 // ignore it 1561 } 1562 } 1563 1564 /** 1565 * Get the value of the flag to automatically write sent/received SMS/MMS messages into system 1566 * 1567 * When this flag is on, all SMS/MMS sent/received are stored by system automatically 1568 * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system 1569 * automatically 1570 * 1571 * @return the current value of the auto persist flag 1572 * {@hide} 1573 */ 1574 public boolean getAutoPersisting() { 1575 try { 1576 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1577 if (iMms != null) { 1578 return iMms.getAutoPersisting(); 1579 } 1580 } catch (RemoteException ex) { 1581 // ignore it 1582 } 1583 return false; 1584 } 1585 1586 /** 1587 * Get carrier-dependent configuration values. 1588 * 1589 * @return bundle key/values pairs of configuration values 1590 */ 1591 public Bundle getCarrierConfigValues() { 1592 try { 1593 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 1594 if (iMms != null) { 1595 return iMms.getCarrierConfigValues(getSubscriptionId()); 1596 } 1597 } catch (RemoteException ex) { 1598 // ignore it 1599 } 1600 return null; 1601 } 1602 1603 /** 1604 * Create a single use app specific incoming SMS request for the the calling package. 1605 * 1606 * This method returns a token that if included in a subsequent incoming SMS message will cause 1607 * {@code intent} to be sent with the SMS data. 1608 * 1609 * The token is only good for one use, after an SMS has been received containing the token all 1610 * subsequent SMS messages with the token will be routed as normal. 1611 * 1612 * An app can only have one request at a time, if the app already has a request pending it will 1613 * be replaced with a new request. 1614 * 1615 * @return Token to include in an SMS message. The token will be 11 characters long. 1616 * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent 1617 */ 1618 public String createAppSpecificSmsToken(PendingIntent intent) { 1619 try { 1620 ISms iccSms = getISmsServiceOrThrow(); 1621 return iccSms.createAppSpecificSmsToken(getSubscriptionId(), 1622 ActivityThread.currentPackageName(), intent); 1623 1624 } catch (RemoteException ex) { 1625 ex.rethrowFromSystemServer(); 1626 return null; 1627 } 1628 } 1629 1630 /** 1631 * Filters a bundle to only contain MMS config variables. 1632 * 1633 * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS 1634 * config and unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the 1635 * supplied bundle. 1636 * 1637 * @param config a Bundle that contains MMS config variables and possibly more. 1638 * @return a new Bundle that only contains the MMS_CONFIG_* keys defined above. 1639 * @hide 1640 */ 1641 public static Bundle getMmsConfig(BaseBundle config) { 1642 Bundle filtered = new Bundle(); 1643 filtered.putBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID, 1644 config.getBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID)); 1645 filtered.putBoolean(MMS_CONFIG_MMS_ENABLED, config.getBoolean(MMS_CONFIG_MMS_ENABLED)); 1646 filtered.putBoolean(MMS_CONFIG_GROUP_MMS_ENABLED, 1647 config.getBoolean(MMS_CONFIG_GROUP_MMS_ENABLED)); 1648 filtered.putBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED, 1649 config.getBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED)); 1650 filtered.putBoolean(MMS_CONFIG_ALIAS_ENABLED, config.getBoolean(MMS_CONFIG_ALIAS_ENABLED)); 1651 filtered.putBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO, 1652 config.getBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO)); 1653 filtered.putBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED, 1654 config.getBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED)); 1655 filtered.putBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED, 1656 config.getBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED)); 1657 filtered.putBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, 1658 config.getBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION)); 1659 filtered.putBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES, 1660 config.getBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES)); 1661 filtered.putBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED, 1662 config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED)); 1663 filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED, 1664 config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED)); 1665 filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION, 1666 config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION)); 1667 filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE)); 1668 filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH)); 1669 filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT)); 1670 filtered.putInt(MMS_CONFIG_RECIPIENT_LIMIT, config.getInt(MMS_CONFIG_RECIPIENT_LIMIT)); 1671 filtered.putInt(MMS_CONFIG_ALIAS_MIN_CHARS, config.getInt(MMS_CONFIG_ALIAS_MIN_CHARS)); 1672 filtered.putInt(MMS_CONFIG_ALIAS_MAX_CHARS, config.getInt(MMS_CONFIG_ALIAS_MAX_CHARS)); 1673 filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD, 1674 config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD)); 1675 filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD, 1676 config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD)); 1677 filtered.putInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE, 1678 config.getInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE)); 1679 filtered.putInt(MMS_CONFIG_SUBJECT_MAX_LENGTH, 1680 config.getInt(MMS_CONFIG_SUBJECT_MAX_LENGTH)); 1681 filtered.putInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT, 1682 config.getInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT)); 1683 filtered.putString(MMS_CONFIG_UA_PROF_TAG_NAME, 1684 config.getString(MMS_CONFIG_UA_PROF_TAG_NAME)); 1685 filtered.putString(MMS_CONFIG_USER_AGENT, config.getString(MMS_CONFIG_USER_AGENT)); 1686 filtered.putString(MMS_CONFIG_UA_PROF_URL, config.getString(MMS_CONFIG_UA_PROF_URL)); 1687 filtered.putString(MMS_CONFIG_HTTP_PARAMS, config.getString(MMS_CONFIG_HTTP_PARAMS)); 1688 filtered.putString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER, 1689 config.getString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER)); 1690 filtered.putString(MMS_CONFIG_NAI_SUFFIX, config.getString(MMS_CONFIG_NAI_SUFFIX)); 1691 filtered.putBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS, 1692 config.getBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS)); 1693 filtered.putBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER, 1694 config.getBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER)); 1695 return filtered; 1696 } 1697 1698} 1699