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