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 17 package android.telephony; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SuppressAutoDoc; 25 import android.annotation.SystemApi; 26 import android.annotation.TestApi; 27 import android.annotation.UnsupportedAppUsage; 28 import android.app.ActivityThread; 29 import android.app.PendingIntent; 30 import android.content.ContentValues; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.pm.PackageManager; 34 import android.database.CursorWindow; 35 import android.net.Uri; 36 import android.os.BaseBundle; 37 import android.os.Binder; 38 import android.os.Build; 39 import android.os.Bundle; 40 import android.os.RemoteException; 41 import android.os.ServiceManager; 42 import android.provider.Telephony; 43 import android.text.TextUtils; 44 import android.util.ArrayMap; 45 import android.util.Log; 46 47 import com.android.internal.telephony.IIntegerConsumer; 48 import com.android.internal.telephony.IMms; 49 import com.android.internal.telephony.ISms; 50 import com.android.internal.telephony.ITelephony; 51 import com.android.internal.telephony.SmsRawData; 52 53 import java.lang.annotation.Retention; 54 import java.lang.annotation.RetentionPolicy; 55 import java.util.ArrayList; 56 import java.util.Arrays; 57 import java.util.List; 58 import java.util.Map; 59 import java.util.concurrent.Executor; 60 61 /* 62 * TODO(code review): Curious question... Why are a lot of these 63 * methods not declared as static, since they do not seem to require 64 * any local object state? Presumably this cannot be changed without 65 * interfering with the API... 66 */ 67 68 /** 69 * Manages SMS operations such as sending data, text, and pdu SMS messages. 70 * Get this object by calling the static method {@link #getDefault()}. To create an instance of 71 * {@link SmsManager} associated with a specific subscription ID, call 72 * {@link #getSmsManagerForSubscriptionId(int)}. This is typically used for devices that support 73 * multiple active subscriptions at once. 74 * 75 * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19) 76 * and higher, see {@link android.provider.Telephony}. 77 * 78 * @see SubscriptionManager#getActiveSubscriptionInfoList() 79 */ 80 public final class SmsManager { 81 private static final String TAG = "SmsManager"; 82 83 /** Singleton object constructed during class initialization. */ 84 private static final SmsManager sInstance = new SmsManager( 85 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 86 private static final Object sLockObject = new Object(); 87 88 /** @hide */ 89 public static final int CELL_BROADCAST_RAN_TYPE_GSM = 0; 90 /** @hide */ 91 public static final int CELL_BROADCAST_RAN_TYPE_CDMA = 1; 92 93 /** SMS record length from TS 51.011 10.5.3 94 * @hide 95 */ 96 public static final int SMS_RECORD_LENGTH = 176; 97 98 /** SMS record length from C.S0023 3.4.27 99 * @hide 100 */ 101 public static final int CDMA_SMS_RECORD_LENGTH = 255; 102 103 private static final Map<Integer, SmsManager> sSubInstances = 104 new ArrayMap<Integer, SmsManager>(); 105 106 /** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */ 107 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 108 private int mSubId; 109 110 /* 111 * Key for the various carrier-dependent configuration values. 112 * Some of the values are used by the system in processing SMS or MMS messages. Others 113 * are provided for the convenience of SMS applications. 114 */ 115 116 /** 117 * Whether to append transaction id to MMS WAP Push M-Notification.ind's content location URI 118 * when constructing the download URL of a new MMS (boolean type) 119 */ 120 public static final String MMS_CONFIG_APPEND_TRANSACTION_ID = 121 CarrierConfigManager.KEY_MMS_APPEND_TRANSACTION_ID_BOOL; 122 /** 123 * Whether MMS is enabled for the current carrier (boolean type) 124 */ 125 public static final String 126 MMS_CONFIG_MMS_ENABLED = CarrierConfigManager.KEY_MMS_MMS_ENABLED_BOOL; 127 /** 128 * Whether group MMS is enabled for the current carrier (boolean type) 129 */ 130 public static final String 131 MMS_CONFIG_GROUP_MMS_ENABLED = CarrierConfigManager.KEY_MMS_GROUP_MMS_ENABLED_BOOL; 132 /** 133 * If this is enabled, M-NotifyResp.ind should be sent to the WAP Push content location instead 134 * of the default MMSC (boolean type) 135 */ 136 public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED = 137 CarrierConfigManager.KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL; 138 /** 139 * Whether alias is enabled (boolean type) 140 */ 141 public static final String 142 MMS_CONFIG_ALIAS_ENABLED = CarrierConfigManager.KEY_MMS_ALIAS_ENABLED_BOOL; 143 /** 144 * Whether audio is allowed to be attached for MMS messages (boolean type) 145 */ 146 public static final String 147 MMS_CONFIG_ALLOW_ATTACH_AUDIO = CarrierConfigManager.KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL; 148 /** 149 * Whether multipart SMS is enabled (boolean type) 150 */ 151 public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED = 152 CarrierConfigManager.KEY_MMS_MULTIPART_SMS_ENABLED_BOOL; 153 /** 154 * Whether SMS delivery report is enabled (boolean type) 155 */ 156 public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED = 157 CarrierConfigManager.KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL; 158 /** 159 * Whether content-disposition field should be expected in an MMS PDU (boolean type) 160 */ 161 public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION = 162 CarrierConfigManager.KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL; 163 /** 164 * Whether multipart SMS should be sent as separate messages 165 */ 166 public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES = 167 CarrierConfigManager.KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL; 168 /** 169 * Whether MMS read report is enabled (boolean type) 170 */ 171 public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED = 172 CarrierConfigManager.KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL; 173 /** 174 * Whether MMS delivery report is enabled (boolean type) 175 */ 176 public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED = 177 CarrierConfigManager.KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL; 178 /** 179 * Max MMS message size in bytes (int type) 180 */ 181 public static final String 182 MMS_CONFIG_MAX_MESSAGE_SIZE = CarrierConfigManager.KEY_MMS_MAX_MESSAGE_SIZE_INT; 183 /** 184 * Max MMS image width (int type) 185 */ 186 public static final String 187 MMS_CONFIG_MAX_IMAGE_WIDTH = CarrierConfigManager.KEY_MMS_MAX_IMAGE_WIDTH_INT; 188 /** 189 * Max MMS image height (int type) 190 */ 191 public static final String 192 MMS_CONFIG_MAX_IMAGE_HEIGHT = CarrierConfigManager.KEY_MMS_MAX_IMAGE_HEIGHT_INT; 193 /** 194 * Limit of recipients of MMS messages (int type) 195 */ 196 public static final String 197 MMS_CONFIG_RECIPIENT_LIMIT = CarrierConfigManager.KEY_MMS_RECIPIENT_LIMIT_INT; 198 /** 199 * Min alias character count (int type) 200 */ 201 public static final String 202 MMS_CONFIG_ALIAS_MIN_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MIN_CHARS_INT; 203 /** 204 * Max alias character count (int type) 205 */ 206 public static final String 207 MMS_CONFIG_ALIAS_MAX_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MAX_CHARS_INT; 208 /** 209 * When the number of parts of a multipart SMS reaches this threshold, it should be converted 210 * into an MMS (int type) 211 */ 212 public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD = 213 CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT; 214 /** 215 * Some carriers require SMS to be converted into MMS when text length reaches this threshold 216 * (int type) 217 */ 218 public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD = 219 CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT; 220 /** 221 * Max message text size (int type) 222 */ 223 public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE = 224 CarrierConfigManager.KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT; 225 /** 226 * Max message subject length (int type) 227 */ 228 public static final String 229 MMS_CONFIG_SUBJECT_MAX_LENGTH = CarrierConfigManager.KEY_MMS_SUBJECT_MAX_LENGTH_INT; 230 /** 231 * MMS HTTP socket timeout in milliseconds (int type) 232 */ 233 public static final String 234 MMS_CONFIG_HTTP_SOCKET_TIMEOUT = CarrierConfigManager.KEY_MMS_HTTP_SOCKET_TIMEOUT_INT; 235 /** 236 * The name of the UA Prof URL HTTP header for MMS HTTP request (String type) 237 */ 238 public static final String 239 MMS_CONFIG_UA_PROF_TAG_NAME = CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING; 240 /** 241 * The User-Agent header value for MMS HTTP request (String type) 242 */ 243 public static final String 244 MMS_CONFIG_USER_AGENT = CarrierConfigManager.KEY_MMS_USER_AGENT_STRING; 245 /** 246 * The UA Profile URL header value for MMS HTTP request (String type) 247 */ 248 public static final String 249 MMS_CONFIG_UA_PROF_URL = CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING; 250 /** 251 * A list of HTTP headers to add to MMS HTTP request, separated by "|" (String type) 252 */ 253 public static final String 254 MMS_CONFIG_HTTP_PARAMS = CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING; 255 /** 256 * Email gateway number (String type) 257 */ 258 public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER = 259 CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING; 260 /** 261 * The suffix to append to the NAI header value for MMS HTTP request (String type) 262 */ 263 public static final String 264 MMS_CONFIG_NAI_SUFFIX = CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING; 265 /** 266 * If true, show the cell broadcast (amber alert) in the SMS settings. Some carriers don't want 267 * this shown. (Boolean type) 268 */ 269 public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS = 270 CarrierConfigManager.KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL; 271 /** 272 * Whether the carrier MMSC supports charset field in Content-Type header. If this is false, 273 * then we don't add "charset" to "Content-Type" 274 */ 275 public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER = 276 CarrierConfigManager.KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL; 277 /** 278 * If true, add "Connection: close" header to MMS HTTP requests so the connection 279 * is immediately closed (disabling keep-alive). (Boolean type) 280 * @hide 281 */ 282 public static final String MMS_CONFIG_CLOSE_CONNECTION = 283 CarrierConfigManager.KEY_MMS_CLOSE_CONNECTION_BOOL; 284 285 /** 286 * 3gpp2 SMS priority is not specified 287 * @hide 288 */ 289 public static final int SMS_MESSAGE_PRIORITY_NOT_SPECIFIED = -1; 290 /** 291 * 3gpp SMS period is not specified 292 * @hide 293 */ 294 public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1; 295 296 /** 297 * Extra key passed into a PendingIntent when the SMS operation failed due to there being no 298 * default set. 299 */ 300 private static final String NO_DEFAULT_EXTRA = "noDefault"; 301 302 // result of asking the user for a subscription to perform an operation. 303 private interface SubscriptionResolverResult { onSuccess(int subId)304 void onSuccess(int subId); onFailure()305 void onFailure(); 306 } 307 308 /** 309 * Send a text based SMS. 310 * 311 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 312 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 313 * 314 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 315 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 316 * writes messages sent using this method to the SMS Provider (the default SMS app is always 317 * responsible for writing its sent messages to the SMS Provider). For information about 318 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 319 * 320 * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this 321 * manager on a multi-SIM device, this operation may fail sending the SMS message because no 322 * suitable default subscription could be found. In this case, if {@code sentIntent} is 323 * non-null, then the {@link PendingIntent} will be sent with an error code 324 * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the 325 * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions 326 * where this operation may fail. 327 * </p> 328 * 329 * 330 * @param destinationAddress the address to send the message to 331 * @param scAddress is the service center address or null to use 332 * the current default SMSC 333 * @param text the body of the message to send 334 * @param sentIntent if not NULL this <code>PendingIntent</code> is 335 * broadcast when the message is successfully sent, or failed. 336 * The result code will be <code>Activity.RESULT_OK</code> for success, 337 * or one of these errors:<br> 338 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 339 * <code>RESULT_ERROR_RADIO_OFF</code><br> 340 * <code>RESULT_ERROR_NULL_PDU</code><br> 341 * <code>RESULT_ERROR_NO_SERVICE</code><br> 342 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 343 * the extra "errorCode" containing a radio technology specific value, 344 * generally only useful for troubleshooting.<br> 345 * The per-application based SMS control checks sentIntent. If sentIntent 346 * is NULL the caller will be checked against all unknown applications, 347 * which cause smaller number of SMS to be sent in checking period. 348 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 349 * broadcast when the message is delivered to the recipient. The 350 * raw pdu of the status report is in the extended data ("pdu"). 351 * 352 * @throws IllegalArgumentException if destinationAddress or text are empty 353 */ sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)354 public void sendTextMessage( 355 String destinationAddress, String scAddress, String text, 356 PendingIntent sentIntent, PendingIntent deliveryIntent) { 357 sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, 358 true /* persistMessage*/, ActivityThread.currentPackageName()); 359 } 360 sendTextMessageInternal(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, String packageName)361 private void sendTextMessageInternal(String destinationAddress, String scAddress, 362 String text, PendingIntent sentIntent, PendingIntent deliveryIntent, 363 boolean persistMessage, String packageName) { 364 if (TextUtils.isEmpty(destinationAddress)) { 365 throw new IllegalArgumentException("Invalid destinationAddress"); 366 } 367 368 if (TextUtils.isEmpty(text)) { 369 throw new IllegalArgumentException("Invalid message body"); 370 } 371 372 final Context context = ActivityThread.currentApplication().getApplicationContext(); 373 // We will only show the SMS disambiguation dialog in the case that the message is being 374 // persisted. This is for two reasons: 375 // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific 376 // subscription and require special permissions. These messages are usually not sent by 377 // the device user and should not have an SMS disambiguation dialog associated with them 378 // because the device user did not trigger them. 379 // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the SEND_SMS 380 // permission. If we call resolveSubscriptionForOperation from a carrier/OEM app that has 381 // the correct MODIFY_PHONE_STATE or carrier permissions, but no SEND_SMS, it will throw 382 // an incorrect SecurityException. 383 if (persistMessage) { 384 resolveSubscriptionForOperation(new SubscriptionResolverResult() { 385 @Override 386 public void onSuccess(int subId) { 387 ISms iSms = getISmsServiceOrThrow(); 388 try { 389 iSms.sendTextForSubscriber(subId, packageName, 390 destinationAddress, scAddress, text, sentIntent, deliveryIntent, 391 persistMessage); 392 } catch (RemoteException e) { 393 Log.e(TAG, "sendTextMessageInternal: Couldn't send SMS, exception - " 394 + e.getMessage()); 395 notifySmsGenericError(sentIntent); 396 } 397 } 398 399 @Override 400 public void onFailure() { 401 notifySmsErrorNoDefaultSet(context, sentIntent); 402 } 403 }); 404 } else { 405 // Not persisting the message, used by sendTextMessageWithoutPersisting() and is not 406 // visible to the user. 407 ISms iSms = getISmsServiceOrThrow(); 408 try { 409 iSms.sendTextForSubscriber(getSubscriptionId(), packageName, 410 destinationAddress, scAddress, text, sentIntent, deliveryIntent, 411 persistMessage); 412 } catch (RemoteException e) { 413 Log.e(TAG, "sendTextMessageInternal (no persist): Couldn't send SMS, exception - " 414 + e.getMessage()); 415 notifySmsGenericError(sentIntent); 416 } 417 } 418 } 419 420 /** 421 * Send a text based SMS without writing it into the SMS Provider. 422 * 423 * <p> 424 * The message will be sent directly over the network and will not be visible in SMS 425 * applications. Intended for internal carrier use only. 426 * </p> 427 * 428 * <p>Requires Permission: Both {@link android.Manifest.permission#SEND_SMS} and 429 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or that the calling app has carrier 430 * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), or that the calling app is 431 * the default IMS app (see 432 * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}). 433 * </p> 434 * 435 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 436 * applications or the Telephony framework and will never trigger an SMS disambiguation 437 * dialog. If this method is called on a device that has multiple active subscriptions, this 438 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 439 * default subscription is defined, the subscription ID associated with this message will be 440 * INVALID, which will result in the SMS being sent on the subscription associated with logical 441 * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the 442 * correct subscription. 443 * </p> 444 * 445 * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent) 446 */ 447 @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges 448 @RequiresPermission(allOf = { 449 android.Manifest.permission.MODIFY_PHONE_STATE, 450 android.Manifest.permission.SEND_SMS 451 }) sendTextMessageWithoutPersisting( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)452 public void sendTextMessageWithoutPersisting( 453 String destinationAddress, String scAddress, String text, 454 PendingIntent sentIntent, PendingIntent deliveryIntent) { 455 sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, 456 false /* persistMessage */, ActivityThread.currentPackageName()); 457 } 458 459 /** 460 * A variant of {@link SmsManager#sendTextMessage} that allows self to be the caller. This is 461 * for internal use only. 462 * 463 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 464 * applications or the Telephony framework and will never trigger an SMS disambiguation 465 * dialog. If this method is called on a device that has multiple active subscriptions, this 466 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 467 * default subscription is defined, the subscription ID associated with this message will be 468 * INVALID, which will result in the SMS being sent on the subscription associated with logical 469 * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the 470 * correct subscription. 471 * </p> 472 * 473 * @param persistMessage whether to persist the sent message in the SMS app. the caller must be 474 * the Phone process if set to false. 475 * 476 * @hide 477 */ sendTextMessageWithSelfPermissions( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage)478 public void sendTextMessageWithSelfPermissions( 479 String destinationAddress, String scAddress, String text, 480 PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage) { 481 if (TextUtils.isEmpty(destinationAddress)) { 482 throw new IllegalArgumentException("Invalid destinationAddress"); 483 } 484 485 if (TextUtils.isEmpty(text)) { 486 throw new IllegalArgumentException("Invalid message body"); 487 } 488 489 try { 490 ISms iSms = getISmsServiceOrThrow(); 491 iSms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(), 492 ActivityThread.currentPackageName(), 493 destinationAddress, 494 scAddress, text, sentIntent, deliveryIntent, persistMessage); 495 } catch (RemoteException ex) { 496 notifySmsGenericError(sentIntent); 497 } 498 } 499 500 /** 501 * Send a text based SMS with messaging options. 502 * 503 * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this 504 * manager on a multi-SIM device, this operation may fail sending the SMS message because no 505 * suitable default subscription could be found. In this case, if {@code sentIntent} is 506 * non-null, then the {@link PendingIntent} will be sent with an error code 507 * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the 508 * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions 509 * where this operation may fail. 510 * </p> 511 * 512 * @param destinationAddress the address to send the message to 513 * @param scAddress is the service center address or null to use 514 * the current default SMSC 515 * @param text the body of the message to send 516 * @param sentIntent if not NULL this <code>PendingIntent</code> is 517 * broadcast when the message is successfully sent, or failed. 518 * The result code will be <code>Activity.RESULT_OK</code> for success, 519 * or one of these errors:<br> 520 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 521 * <code>RESULT_ERROR_RADIO_OFF</code><br> 522 * <code>RESULT_ERROR_NULL_PDU</code><br> 523 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 524 * the extra "errorCode" containing a radio technology specific value, 525 * generally only useful for troubleshooting.<br> 526 * The per-application based SMS control checks sentIntent. If sentIntent 527 * is NULL the caller will be checked against all unknown applications, 528 * which cause smaller number of SMS to be sent in checking period. 529 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 530 * broadcast when the message is delivered to the recipient. The 531 * raw pdu of the status report is in the extended data ("pdu"). 532 * @param priority Priority level of the message 533 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 534 * --------------------------------- 535 * PRIORITY | Level of Priority 536 * --------------------------------- 537 * '00' | Normal 538 * '01' | Interactive 539 * '10' | Urgent 540 * '11' | Emergency 541 * ---------------------------------- 542 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 543 * @param expectMore is a boolean to indicate the sending messages through same link or not. 544 * @param validityPeriod Validity Period of the message in mins. 545 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 546 * Validity Period(Minimum) -> 5 mins 547 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 548 * Any Other values included Negative considered as Invalid Validity Period of the message. 549 * 550 * @throws IllegalArgumentException if destinationAddress or text are empty 551 * {@hide} 552 */ 553 @UnsupportedAppUsage sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority, boolean expectMore, int validityPeriod)554 public void sendTextMessage( 555 String destinationAddress, String scAddress, String text, 556 PendingIntent sentIntent, PendingIntent deliveryIntent, 557 int priority, boolean expectMore, int validityPeriod) { 558 sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, 559 true /* persistMessage*/, priority, expectMore, validityPeriod); 560 } 561 sendTextMessageInternal( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, int priority, boolean expectMore, int validityPeriod)562 private void sendTextMessageInternal( 563 String destinationAddress, String scAddress, String text, 564 PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, 565 int priority, boolean expectMore, int validityPeriod) { 566 if (TextUtils.isEmpty(destinationAddress)) { 567 throw new IllegalArgumentException("Invalid destinationAddress"); 568 } 569 570 if (TextUtils.isEmpty(text)) { 571 throw new IllegalArgumentException("Invalid message body"); 572 } 573 574 if (priority < 0x00 || priority > 0x03) { 575 priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; 576 } 577 578 if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { 579 validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED; 580 } 581 582 final int finalPriority = priority; 583 final int finalValidity = validityPeriod; 584 final Context context = ActivityThread.currentApplication().getApplicationContext(); 585 // We will only show the SMS disambiguation dialog in the case that the message is being 586 // persisted. This is for two reasons: 587 // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific 588 // subscription and require special permissions. These messages are usually not sent by 589 // the device user and should not have an SMS disambiguation dialog associated with them 590 // because the device user did not trigger them. 591 // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the SEND_SMS 592 // permission. If we call resolveSubscriptionForOperation from a carrier/OEM app that has 593 // the correct MODIFY_PHONE_STATE or carrier permissions, but no SEND_SMS, it will throw 594 // an incorrect SecurityException. 595 if (persistMessage) { 596 resolveSubscriptionForOperation(new SubscriptionResolverResult() { 597 @Override 598 public void onSuccess(int subId) { 599 try { 600 ISms iSms = getISmsServiceOrThrow(); 601 if (iSms != null) { 602 iSms.sendTextForSubscriberWithOptions(subId, 603 ActivityThread.currentPackageName(), destinationAddress, 604 scAddress, 605 text, sentIntent, deliveryIntent, persistMessage, finalPriority, 606 expectMore, finalValidity); 607 } 608 } catch (RemoteException e) { 609 Log.e(TAG, "sendTextMessageInternal: Couldn't send SMS, exception - " 610 + e.getMessage()); 611 notifySmsGenericError(sentIntent); 612 } 613 } 614 615 @Override 616 public void onFailure() { 617 notifySmsErrorNoDefaultSet(context, sentIntent); 618 } 619 }); 620 } else { 621 try { 622 ISms iSms = getISmsServiceOrThrow(); 623 if (iSms != null) { 624 iSms.sendTextForSubscriberWithOptions(getSubscriptionId(), 625 ActivityThread.currentPackageName(), destinationAddress, 626 scAddress, 627 text, sentIntent, deliveryIntent, persistMessage, finalPriority, 628 expectMore, finalValidity); 629 } 630 } catch (RemoteException e) { 631 Log.e(TAG, "sendTextMessageInternal(no persist): Couldn't send SMS, exception - " 632 + e.getMessage()); 633 notifySmsGenericError(sentIntent); 634 } 635 } 636 } 637 638 /** 639 * Send a text based SMS without writing it into the SMS Provider. 640 * 641 * <p>Requires Permission: 642 * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier 643 * privileges. 644 * </p> 645 * 646 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 647 * applications or the Telephony framework and will never trigger an SMS disambiguation 648 * dialog. If this method is called on a device that has multiple active subscriptions, this 649 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 650 * default subscription is defined, the subscription ID associated with this message will be 651 * INVALID, which will result in the SMS being sent on the subscription associated with logical 652 * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the 653 * correct subscription. 654 * </p> 655 * 656 * @see #sendTextMessage(String, String, String, PendingIntent, 657 * PendingIntent, int, boolean, int) 658 * @hide 659 */ 660 @UnsupportedAppUsage sendTextMessageWithoutPersisting( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority, boolean expectMore, int validityPeriod)661 public void sendTextMessageWithoutPersisting( 662 String destinationAddress, String scAddress, String text, 663 PendingIntent sentIntent, PendingIntent deliveryIntent, int priority, 664 boolean expectMore, int validityPeriod) { 665 sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, 666 false /* persistMessage */, priority, expectMore, validityPeriod); 667 } 668 669 /** 670 * 671 * Inject an SMS PDU into the android application framework. 672 * 673 * <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier 674 * privileges per {@link android.telephony.TelephonyManager#hasCarrierPrivileges}. 675 * 676 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 677 * applications or the Telephony framework and will never trigger an SMS disambiguation 678 * dialog. If this method is called on a device that has multiple active subscriptions, this 679 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 680 * default subscription is defined, the subscription ID associated with this message will be 681 * INVALID, which will result in the SMS being injected on the subscription associated with 682 * logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is 683 * delivered to the correct subscription. 684 * </p> 685 * 686 * @param pdu is the byte array of pdu to be injected into android application framework 687 * @param format is the format of SMS pdu ({@link SmsMessage#FORMAT_3GPP} or 688 * {@link SmsMessage#FORMAT_3GPP2}) 689 * @param receivedIntent if not NULL this <code>PendingIntent</code> is 690 * broadcast when the message is successfully received by the 691 * android application framework, or failed. This intent is broadcasted at 692 * the same time an SMS received from radio is acknowledged back. 693 * The result code will be {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_HANDLED} 694 * for success, or {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_GENERIC_ERROR} for 695 * error. 696 * 697 * @throws IllegalArgumentException if the format is invalid. 698 */ injectSmsPdu( byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent)699 public void injectSmsPdu( 700 byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent) { 701 if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) { 702 // Format must be either 3gpp or 3gpp2. 703 throw new IllegalArgumentException( 704 "Invalid pdu format. format must be either 3gpp or 3gpp2"); 705 } 706 try { 707 ISms iSms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 708 if (iSms != null) { 709 iSms.injectSmsPduForSubscriber( 710 getSubscriptionId(), pdu, format, receivedIntent); 711 } 712 } catch (RemoteException ex) { 713 try { 714 if (receivedIntent != null) { 715 receivedIntent.send(Telephony.Sms.Intents.RESULT_SMS_GENERIC_ERROR); 716 } 717 } catch (PendingIntent.CanceledException cx) { 718 // Don't worry about it, we do not need to notify the caller if this is the case. 719 } 720 } 721 } 722 723 /** 724 * Divide a message text into several fragments, none bigger than the maximum SMS message size. 725 * 726 * @param text the original message. Must not be null. 727 * @return an <code>ArrayList</code> of strings that, in order, comprise the original message. 728 * @throws IllegalArgumentException if text is null. 729 */ divideMessage(String text)730 public ArrayList<String> divideMessage(String text) { 731 if (null == text) { 732 throw new IllegalArgumentException("text is null"); 733 } 734 return SmsMessage.fragmentText(text, getSubscriptionId()); 735 } 736 737 /** 738 * Send a multi-part text based SMS. The callee should have already 739 * divided the message into correctly sized parts by calling 740 * <code>divideMessage</code>. 741 * 742 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 743 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 744 * 745 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 746 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 747 * writes messages sent using this method to the SMS Provider (the default SMS app is always 748 * responsible for writing its sent messages to the SMS Provider). For information about 749 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 750 * 751 * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this 752 * manager on a multi-SIM device, this operation may fail sending the SMS message because no 753 * suitable default subscription could be found. In this case, if {@code sentIntent} is 754 * non-null, then the {@link PendingIntent} will be sent with an error code 755 * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the 756 * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions 757 * where this operation may fail. 758 * </p> 759 * 760 * 761 * @param destinationAddress the address to send the message to 762 * @param scAddress is the service center address or null to use 763 * the current default SMSC 764 * @param parts an <code>ArrayList</code> of strings that, in order, 765 * comprise the original message 766 * @param sentIntents if not null, an <code>ArrayList</code> of 767 * <code>PendingIntent</code>s (one for each message part) that is 768 * broadcast when the corresponding message part has been sent. 769 * The result code will be <code>Activity.RESULT_OK</code> for success, 770 * or one of these errors:<br> 771 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 772 * <code>RESULT_ERROR_RADIO_OFF</code><br> 773 * <code>RESULT_ERROR_NULL_PDU</code><br> 774 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 775 * the extra "errorCode" containing a radio technology specific value, 776 * generally only useful for troubleshooting.<br> 777 * The per-application based SMS control checks sentIntent. If sentIntent 778 * is NULL the caller will be checked against all unknown applications, 779 * which cause smaller number of SMS to be sent in checking period. 780 * @param deliveryIntents if not null, an <code>ArrayList</code> of 781 * <code>PendingIntent</code>s (one for each message part) that is 782 * broadcast when the corresponding message part has been delivered 783 * to the recipient. The raw pdu of the status report is in the 784 * extended data ("pdu"). 785 * 786 * @throws IllegalArgumentException if destinationAddress or data are empty 787 */ sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)788 public void sendMultipartTextMessage( 789 String destinationAddress, String scAddress, ArrayList<String> parts, 790 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 791 sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, 792 deliveryIntents, true /* persistMessage*/, ActivityThread.currentPackageName()); 793 } 794 795 /** 796 * Similar method as #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList) 797 * With an additional argument. 798 * 799 * <p class="note"><strong>Note:</strong> This method is intended for internal use the Telephony 800 * framework and will never trigger an SMS disambiguation dialog. If this method is called on a 801 * device that has multiple active subscriptions, this {@link SmsManager} instance has been 802 * created with {@link #getDefault()}, and no user-defined default subscription is defined, the 803 * subscription ID associated with this message will be INVALID, which will result in the SMS 804 * being sent on the subscription associated with logical slot 0. Use 805 * {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the correct 806 * subscription. 807 * </p> 808 * 809 * @param packageName serves as the default package name if 810 * {@link ActivityThread#currentPackageName()} is null. 811 * @hide 812 */ sendMultipartTextMessageExternal( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, String packageName)813 public void sendMultipartTextMessageExternal( 814 String destinationAddress, String scAddress, ArrayList<String> parts, 815 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, 816 String packageName) { 817 sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, 818 deliveryIntents, true /* persistMessage*/, 819 ActivityThread.currentPackageName() == null 820 ? packageName : ActivityThread.currentPackageName()); 821 } 822 sendMultipartTextMessageInternal( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessage, String packageName)823 private void sendMultipartTextMessageInternal( 824 String destinationAddress, String scAddress, List<String> parts, 825 List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, 826 boolean persistMessage, String packageName) { 827 if (TextUtils.isEmpty(destinationAddress)) { 828 throw new IllegalArgumentException("Invalid destinationAddress"); 829 } 830 if (parts == null || parts.size() < 1) { 831 throw new IllegalArgumentException("Invalid message body"); 832 } 833 834 if (parts.size() > 1) { 835 final Context context = ActivityThread.currentApplication().getApplicationContext(); 836 // We will only show the SMS disambiguation dialog in the case that the message is being 837 // persisted. This is for two reasons: 838 // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific 839 // subscription and require special permissions. These messages are usually not sent 840 // by the device user and should not have an SMS disambiguation dialog associated 841 // with them because the device user did not trigger them. 842 // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the 843 // SEND_SMS permission. If we call resolveSubscriptionForOperation from a carrier/OEM 844 // app that has the correct MODIFY_PHONE_STATE or carrier permissions, but no 845 // SEND_SMS, it will throw an incorrect SecurityException. 846 if (persistMessage) { 847 resolveSubscriptionForOperation(new SubscriptionResolverResult() { 848 @Override 849 public void onSuccess(int subId) { 850 try { 851 ISms iSms = getISmsServiceOrThrow(); 852 iSms.sendMultipartTextForSubscriber(subId, packageName, 853 destinationAddress, scAddress, parts, sentIntents, 854 deliveryIntents, persistMessage); 855 } catch (RemoteException e) { 856 Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - " 857 + e.getMessage()); 858 notifySmsGenericError(sentIntents); 859 } 860 } 861 862 @Override 863 public void onFailure() { 864 notifySmsErrorNoDefaultSet(context, sentIntents); 865 } 866 }); 867 } else { 868 // Called by apps that are not user facing, don't show disambiguation dialog. 869 try { 870 ISms iSms = getISmsServiceOrThrow(); 871 if (iSms != null) { 872 iSms.sendMultipartTextForSubscriber(getSubscriptionId(), packageName, 873 destinationAddress, scAddress, parts, sentIntents, deliveryIntents, 874 persistMessage); 875 } 876 } catch (RemoteException e) { 877 Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - " 878 + e.getMessage()); 879 notifySmsGenericError(sentIntents); 880 } 881 } 882 } else { 883 PendingIntent sentIntent = null; 884 PendingIntent deliveryIntent = null; 885 if (sentIntents != null && sentIntents.size() > 0) { 886 sentIntent = sentIntents.get(0); 887 } 888 if (deliveryIntents != null && deliveryIntents.size() > 0) { 889 deliveryIntent = deliveryIntents.get(0); 890 } 891 sendTextMessageInternal(destinationAddress, scAddress, parts.get(0), 892 sentIntent, deliveryIntent, true, packageName); 893 } 894 } 895 896 /** 897 * Send a multi-part text based SMS without writing it into the SMS Provider. 898 * 899 * <p> 900 * If this method is called on a device with multiple active subscriptions, this 901 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 902 * default subscription is defined, the subscription ID associated with this message will be 903 * INVALID, which will result in the SMS sent on the subscription associated with slot 904 * 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent using the 905 * correct subscription. 906 * </p> 907 * 908 * <p>Requires Permission: 909 * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier 910 * privileges. 911 * </p> 912 * 913 * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList) 914 * @hide 915 **/ 916 @SystemApi 917 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) sendMultipartTextMessageWithoutPersisting( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)918 public void sendMultipartTextMessageWithoutPersisting( 919 String destinationAddress, String scAddress, List<String> parts, 920 List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { 921 sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, 922 deliveryIntents, false /* persistMessage*/, ActivityThread.currentPackageName()); 923 } 924 925 /** 926 * Send a multi-part text based SMS with messaging options. The callee should have already 927 * divided the message into correctly sized parts by calling 928 * <code>divideMessage</code>. 929 * 930 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 931 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 932 * 933 * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if 934 * <em>and only if</em> an app is not selected as the default SMS app, the system automatically 935 * writes messages sent using this method to the SMS Provider (the default SMS app is always 936 * responsible for writing its sent messages to the SMS Provider). For information about 937 * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> 938 * 939 * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this 940 * manager on a multi-SIM device, this operation may fail sending the SMS message because no 941 * suitable default subscription could be found. In this case, if {@code sentIntent} is 942 * non-null, then the {@link PendingIntent} will be sent with an error code 943 * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the 944 * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions 945 * where this operation may fail. 946 * </p> 947 948 * @param destinationAddress the address to send the message to 949 * @param scAddress is the service center address or null to use 950 * the current default SMSC 951 * @param parts an <code>ArrayList</code> of strings that, in order, 952 * comprise the original message 953 * @param sentIntents if not null, an <code>ArrayList</code> of 954 * <code>PendingIntent</code>s (one for each message part) that is 955 * broadcast when the corresponding message part has been sent. 956 * The result code will be <code>Activity.RESULT_OK</code> for success, 957 * or one of these errors:<br> 958 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 959 * <code>RESULT_ERROR_RADIO_OFF</code><br> 960 * <code>RESULT_ERROR_NULL_PDU</code><br> 961 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 962 * the extra "errorCode" containing a radio technology specific value, 963 * generally only useful for troubleshooting.<br> 964 * The per-application based SMS control checks sentIntent. If sentIntent 965 * is NULL the caller will be checked against all unknown applications, 966 * which cause smaller number of SMS to be sent in checking period. 967 * @param deliveryIntents if not null, an <code>ArrayList</code> of 968 * <code>PendingIntent</code>s (one for each message part) that is 969 * broadcast when the corresponding message part has been delivered 970 * to the recipient. The raw pdu of the status report is in the 971 * extended data ("pdu"). 972 * @param priority Priority level of the message 973 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 974 * --------------------------------- 975 * PRIORITY | Level of Priority 976 * --------------------------------- 977 * '00' | Normal 978 * '01' | Interactive 979 * '10' | Urgent 980 * '11' | Emergency 981 * ---------------------------------- 982 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 983 * @param expectMore is a boolean to indicate the sending messages through same link or not. 984 * @param validityPeriod Validity Period of the message in mins. 985 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 986 * Validity Period(Minimum) -> 5 mins 987 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 988 * Any Other values included Negative considered as Invalid Validity Period of the message. 989 * 990 * @throws IllegalArgumentException if destinationAddress or data are empty 991 * {@hide} 992 */ 993 @UnsupportedAppUsage sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, int priority, boolean expectMore, int validityPeriod)994 public void sendMultipartTextMessage( 995 String destinationAddress, String scAddress, ArrayList<String> parts, 996 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, 997 int priority, boolean expectMore, int validityPeriod) { 998 sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, 999 deliveryIntents, true /* persistMessage*/, priority, expectMore, 1000 validityPeriod); 1001 } 1002 sendMultipartTextMessageInternal( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessage, int priority, boolean expectMore, int validityPeriod)1003 private void sendMultipartTextMessageInternal( 1004 String destinationAddress, String scAddress, List<String> parts, 1005 List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, 1006 boolean persistMessage, int priority, boolean expectMore, int validityPeriod) { 1007 if (TextUtils.isEmpty(destinationAddress)) { 1008 throw new IllegalArgumentException("Invalid destinationAddress"); 1009 } 1010 if (parts == null || parts.size() < 1) { 1011 throw new IllegalArgumentException("Invalid message body"); 1012 } 1013 1014 if (priority < 0x00 || priority > 0x03) { 1015 priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; 1016 } 1017 1018 if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { 1019 validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED; 1020 } 1021 1022 if (parts.size() > 1) { 1023 final int finalPriority = priority; 1024 final int finalValidity = validityPeriod; 1025 final Context context = ActivityThread.currentApplication().getApplicationContext(); 1026 if (persistMessage) { 1027 resolveSubscriptionForOperation(new SubscriptionResolverResult() { 1028 @Override 1029 public void onSuccess(int subId) { 1030 try { 1031 ISms iSms = getISmsServiceOrThrow(); 1032 if (iSms != null) { 1033 iSms.sendMultipartTextForSubscriberWithOptions(subId, 1034 ActivityThread.currentPackageName(), destinationAddress, 1035 scAddress, parts, sentIntents, deliveryIntents, 1036 persistMessage, finalPriority, expectMore, finalValidity); 1037 } 1038 } catch (RemoteException e) { 1039 Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - " 1040 + e.getMessage()); 1041 notifySmsGenericError(sentIntents); 1042 } 1043 } 1044 1045 @Override 1046 public void onFailure() { 1047 notifySmsErrorNoDefaultSet(context, sentIntents); 1048 } 1049 }); 1050 } else { 1051 // Sent by apps that are not user visible, so don't show SIM disambiguation dialog. 1052 try { 1053 ISms iSms = getISmsServiceOrThrow(); 1054 if (iSms != null) { 1055 iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(), 1056 ActivityThread.currentPackageName(), destinationAddress, 1057 scAddress, parts, sentIntents, deliveryIntents, 1058 persistMessage, finalPriority, expectMore, finalValidity); 1059 } 1060 } catch (RemoteException e) { 1061 Log.e(TAG, "sendMultipartTextMessageInternal (no persist): Couldn't send SMS - " 1062 + e.getMessage()); 1063 notifySmsGenericError(sentIntents); 1064 } 1065 } 1066 } else { 1067 PendingIntent sentIntent = null; 1068 PendingIntent deliveryIntent = null; 1069 if (sentIntents != null && sentIntents.size() > 0) { 1070 sentIntent = sentIntents.get(0); 1071 } 1072 if (deliveryIntents != null && deliveryIntents.size() > 0) { 1073 deliveryIntent = deliveryIntents.get(0); 1074 } 1075 sendTextMessageInternal(destinationAddress, scAddress, parts.get(0), 1076 sentIntent, deliveryIntent, persistMessage, priority, expectMore, 1077 validityPeriod); 1078 } 1079 } 1080 1081 /** 1082 * Send a multi-part text based SMS without writing it into the SMS Provider. 1083 * 1084 * <p>Requires Permission: 1085 * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier 1086 * privileges. 1087 * </p> 1088 * 1089 * <p class="note"><strong>Note:</strong> This method is intended for internal use the Telephony 1090 * framework and will never trigger an SMS disambiguation dialog. If this method is called on a 1091 * device that has multiple active subscriptions, this {@link SmsManager} instance has been 1092 * created with {@link #getDefault()}, and no user-defined default subscription is defined, the 1093 * subscription ID associated with this message will be INVALID, which will result in the SMS 1094 * being sent on the subscription associated with logical slot 0. Use 1095 * {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the correct 1096 * subscription. 1097 * </p> 1098 * 1099 * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, 1100 * ArrayList, int, boolean, int) 1101 * @hide 1102 **/ sendMultipartTextMessageWithoutPersisting( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, int priority, boolean expectMore, int validityPeriod)1103 public void sendMultipartTextMessageWithoutPersisting( 1104 String destinationAddress, String scAddress, List<String> parts, 1105 List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, 1106 int priority, boolean expectMore, int validityPeriod) { 1107 sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, 1108 deliveryIntents, false /* persistMessage*/, priority, expectMore, 1109 validityPeriod); 1110 } 1111 1112 /** 1113 * Send a data based SMS to a specific application port. 1114 * 1115 * <p class="note"><strong>Note:</strong> Using this method requires that your app has the 1116 * {@link android.Manifest.permission#SEND_SMS} permission.</p> 1117 * 1118 * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this 1119 * manager on a multi-SIM device, this operation may fail sending the SMS message because no 1120 * suitable default subscription could be found. In this case, if {@code sentIntent} is 1121 * non-null, then the {@link PendingIntent} will be sent with an error code 1122 * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the 1123 * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions 1124 * where this operation may fail. 1125 * </p> 1126 * 1127 * @param destinationAddress the address to send the message to 1128 * @param scAddress is the service center address or null to use 1129 * the current default SMSC 1130 * @param destinationPort the port to deliver the message to 1131 * @param data the body of the message to send 1132 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1133 * broadcast when the message is successfully sent, or failed. 1134 * The result code will be <code>Activity.RESULT_OK</code> for success, 1135 * or one of these errors:<br> 1136 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 1137 * <code>RESULT_ERROR_RADIO_OFF</code><br> 1138 * <code>RESULT_ERROR_NULL_PDU</code><br> 1139 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 1140 * the extra "errorCode" containing a radio technology specific value, 1141 * generally only useful for troubleshooting.<br> 1142 * The per-application based SMS control checks sentIntent. If sentIntent 1143 * is NULL the caller will be checked against all unknown applications, 1144 * which cause smaller number of SMS to be sent in checking period. 1145 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1146 * broadcast when the message is delivered to the recipient. The 1147 * raw pdu of the status report is in the extended data ("pdu"). 1148 * 1149 * @throws IllegalArgumentException if destinationAddress or data are empty 1150 */ sendDataMessage( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)1151 public void sendDataMessage( 1152 String destinationAddress, String scAddress, short destinationPort, 1153 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 1154 if (TextUtils.isEmpty(destinationAddress)) { 1155 throw new IllegalArgumentException("Invalid destinationAddress"); 1156 } 1157 1158 if (data == null || data.length == 0) { 1159 throw new IllegalArgumentException("Invalid message data"); 1160 } 1161 1162 final Context context = ActivityThread.currentApplication().getApplicationContext(); 1163 resolveSubscriptionForOperation(new SubscriptionResolverResult() { 1164 @Override 1165 public void onSuccess(int subId) { 1166 try { 1167 ISms iSms = getISmsServiceOrThrow(); 1168 iSms.sendDataForSubscriber(subId, ActivityThread.currentPackageName(), 1169 destinationAddress, scAddress, destinationPort & 0xFFFF, data, 1170 sentIntent, deliveryIntent); 1171 } catch (RemoteException e) { 1172 Log.e(TAG, "sendDataMessage: Couldn't send SMS - Exception: " + e.getMessage()); 1173 notifySmsGenericError(sentIntent); 1174 } 1175 } 1176 @Override 1177 public void onFailure() { 1178 notifySmsErrorNoDefaultSet(context, sentIntent); 1179 } 1180 }); 1181 } 1182 1183 /** 1184 * A variant of {@link SmsManager#sendDataMessage} that allows self to be the caller. This is 1185 * for internal use only. 1186 * 1187 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1188 * applications or the Telephony framework and will never trigger an SMS disambiguation 1189 * dialog. If this method is called on a device that has multiple active subscriptions, this 1190 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1191 * default subscription is defined, the subscription ID associated with this message will be 1192 * INVALID, which will result in the SMS being sent on the subscription associated with logical 1193 * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the 1194 * correct subscription. 1195 * </p> 1196 * 1197 * @hide 1198 */ sendDataMessageWithSelfPermissions( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)1199 public void sendDataMessageWithSelfPermissions( 1200 String destinationAddress, String scAddress, short destinationPort, 1201 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 1202 if (TextUtils.isEmpty(destinationAddress)) { 1203 throw new IllegalArgumentException("Invalid destinationAddress"); 1204 } 1205 1206 if (data == null || data.length == 0) { 1207 throw new IllegalArgumentException("Invalid message data"); 1208 } 1209 1210 try { 1211 ISms iSms = getISmsServiceOrThrow(); 1212 iSms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(), 1213 ActivityThread.currentPackageName(), destinationAddress, scAddress, 1214 destinationPort & 0xFFFF, data, sentIntent, deliveryIntent); 1215 } catch (RemoteException e) { 1216 Log.e(TAG, "sendDataMessageWithSelfPermissions: Couldn't send SMS - Exception: " 1217 + e.getMessage()); 1218 notifySmsGenericError(sentIntent); 1219 } 1220 } 1221 1222 /** 1223 * Get the SmsManager associated with the default subscription id. The instance will always be 1224 * associated with the default subscription id, even if the default subscription id changes. 1225 * 1226 * <p class="note"><strong>Note:</strong> For devices that support multiple active subscriptions 1227 * at a time, SmsManager will track the subscription set by the user as the default SMS 1228 * subscription. If the user has not set a default, {@link SmsManager} may 1229 * start an activity to kick off a subscription disambiguation dialog. Most operations will not 1230 * complete until the user has chosen the subscription that will be associated with the 1231 * operation. If the user cancels the dialog without choosing a subscription, one of the 1232 * following will happen, depending on the target SDK version of the application. For 1233 * compatibility purposes, if the target SDK level is <= 28, telephony will still send the SMS 1234 * over the first available subscription. If the target SDK level is > 28, the operation will 1235 * fail to complete. 1236 * </p> 1237 * 1238 * <p class="note"><strong>Note:</strong> If this method is used to perform an operation on a 1239 * device that has multiple active subscriptions, the user has not set a default SMS 1240 * subscription, and the operation is being performed while the application is not in the 1241 * foreground, the SMS disambiguation dialog will not be shown. The result of the operation will 1242 * conclude as if the user cancelled the disambiguation dialog and the operation will finish as 1243 * outlined above, depending on the target SDK version of the calling application. It is safer 1244 * to use {@link #getSmsManagerForSubscriptionId(int)} if the application will perform the 1245 * operation while in the background because this can cause unpredictable results, such as the 1246 * operation being sent over the wrong subscription or failing completely, depending on the 1247 * user's default SMS subscription setting. 1248 * </p> 1249 * 1250 * @return the {@link SmsManager} associated with the default subscription id. 1251 * 1252 * @see SubscriptionManager#getDefaultSmsSubscriptionId() 1253 */ getDefault()1254 public static SmsManager getDefault() { 1255 return sInstance; 1256 } 1257 1258 /** 1259 * Get the instance of the SmsManager associated with a particular subscription ID. 1260 * 1261 * <p class="note"><strong>Note:</strong> Constructing an {@link SmsManager} in this manner will 1262 * never cause an SMS disambiguation dialog to appear, unlike {@link #getDefault()}. 1263 * </p> 1264 * 1265 * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager} 1266 * @return the instance of the SmsManager associated with subscription 1267 * 1268 * @see SubscriptionManager#getActiveSubscriptionInfoList() 1269 * @see SubscriptionManager#getDefaultSmsSubscriptionId() 1270 */ getSmsManagerForSubscriptionId(int subId)1271 public static SmsManager getSmsManagerForSubscriptionId(int subId) { 1272 synchronized(sLockObject) { 1273 SmsManager smsManager = sSubInstances.get(subId); 1274 if (smsManager == null) { 1275 smsManager = new SmsManager(subId); 1276 sSubInstances.put(subId, smsManager); 1277 } 1278 return smsManager; 1279 } 1280 } 1281 SmsManager(int subId)1282 private SmsManager(int subId) { 1283 mSubId = subId; 1284 } 1285 1286 /** 1287 * Get the associated subscription id. If the instance was returned by {@link #getDefault()}, 1288 * then this method may return different values at different points in time (if the user 1289 * changes the default subscription id). 1290 * 1291 * <p class="note"><strong>Note:</strong> This method used to display a disambiguation dialog to 1292 * the user asking them to choose a default subscription to send SMS messages over if they 1293 * haven't chosen yet. Starting in API level 29, we allow the user to not have a default set as 1294 * a valid option for the default SMS subscription on multi-SIM devices. We no longer show the 1295 * disambiguation dialog and return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if the 1296 * device has multiple active subscriptions and no default is set. 1297 * </p> 1298 * 1299 * @return associated subscription ID or {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if 1300 * the default subscription id cannot be determined or the device has multiple active 1301 * subscriptions and and no default is set ("ask every time") by the user. 1302 */ getSubscriptionId()1303 public int getSubscriptionId() { 1304 try { 1305 return (mSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) 1306 ? getISmsServiceOrThrow().getPreferredSmsSubscription() : mSubId; 1307 } catch (RemoteException e) { 1308 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 1309 } 1310 } 1311 1312 /** 1313 * Resolves the subscription id to use for the associated operation if 1314 * {@link #getSubscriptionId()} returns {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. 1315 * 1316 * If app targets API level 28 or below and they are either sending the SMS from the background 1317 * or the device has more than one active subscription available and no default is set, we will 1318 * use the first logical slot to send the SMS and possibly fail later in the SMS sending 1319 * process. 1320 * 1321 * Regardless of the API level, if the app is the foreground app, then we will show the SMS 1322 * disambiguation dialog. If the app is in the background and tries to perform an operation, we 1323 * will not show the disambiguation dialog. 1324 * 1325 * See {@link #getDefault()} for a detailed explanation of how this method operates. 1326 * 1327 * @param resolverResult The callback that will be called when the subscription is resolved or 1328 * fails to be resolved. 1329 */ resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult)1330 private void resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult) { 1331 int subId = getSubscriptionId(); 1332 boolean isSmsSimPickActivityNeeded = false; 1333 final Context context = ActivityThread.currentApplication().getApplicationContext(); 1334 try { 1335 ISms iSms = getISmsService(); 1336 if (iSms != null) { 1337 // Determines if the SMS SIM pick activity should be shown. This is only shown if: 1338 // 1) The device has multiple active subscriptions and an SMS default subscription 1339 // hasn't been set, and 1340 // 2) SmsManager is being called from the foreground app. 1341 // Android does not allow background activity starts, so we need to block this. 1342 // if Q+, do not perform requested operation if these two operations are not set. If 1343 // <P, perform these operations on phone 0 (for compatibility purposes, since we 1344 // used to not wait for the result of this activity). 1345 isSmsSimPickActivityNeeded = iSms.isSmsSimPickActivityNeeded(subId); 1346 } 1347 } catch (RemoteException ex) { 1348 Log.e(TAG, "resolveSubscriptionForOperation", ex); 1349 } 1350 if (!isSmsSimPickActivityNeeded) { 1351 sendResolverResult(resolverResult, subId, false /*pickActivityShown*/); 1352 return; 1353 } 1354 // We need to ask the user pick an appropriate subid for the operation. 1355 Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for package " 1356 + context.getPackageName()); 1357 try { 1358 // Create the SMS pick activity and call back once the activity is complete. Can't do 1359 // it here because we do not have access to the activity context that is performing this 1360 // operation. 1361 // Requires that the calling process has the SEND_SMS permission. 1362 getITelephony().enqueueSmsPickResult(context.getOpPackageName(), 1363 new IIntegerConsumer.Stub() { 1364 @Override 1365 public void accept(int subId) { 1366 // Runs on binder thread attached to this app's process. 1367 sendResolverResult(resolverResult, subId, true /*pickActivityShown*/); 1368 } 1369 }); 1370 } catch (RemoteException ex) { 1371 Log.e(TAG, "Unable to launch activity", ex); 1372 // pickActivityShown is true here because we want to call sendResolverResult and always 1373 // have this operation fail. This is because we received a RemoteException here, which 1374 // means that telephony is not available and the next operation to Telephony will fail 1375 // as well anyways, so we might as well shortcut fail here first. 1376 sendResolverResult(resolverResult, subId, true /*pickActivityShown*/); 1377 } 1378 } 1379 sendResolverResult(SubscriptionResolverResult resolverResult, int subId, boolean pickActivityShown)1380 private void sendResolverResult(SubscriptionResolverResult resolverResult, int subId, 1381 boolean pickActivityShown) { 1382 if (SubscriptionManager.isValidSubscriptionId(subId)) { 1383 resolverResult.onSuccess(subId); 1384 return; 1385 } 1386 1387 if (getTargetSdkVersion() <= Build.VERSION_CODES.P && !pickActivityShown) { 1388 // Do not fail, return a success with an INVALID subid for apps targeting P or below 1389 // that tried to perform an operation and the SMS disambiguation dialog was never shown, 1390 // as these applications may not have been written to handle the failure case properly. 1391 // This will resolve to performing the operation on phone 0 in telephony. 1392 resolverResult.onSuccess(subId); 1393 } else { 1394 // Fail if the app targets Q or above or it targets P and below and the disambiguation 1395 // dialog was shown and the user clicked out of it. 1396 resolverResult.onFailure(); 1397 } 1398 } 1399 getTargetSdkVersion()1400 private static int getTargetSdkVersion() { 1401 final Context context = ActivityThread.currentApplication().getApplicationContext(); 1402 int targetSdk; 1403 try { 1404 targetSdk = context.getPackageManager().getApplicationInfo( 1405 context.getOpPackageName(), 0).targetSdkVersion; 1406 } catch (PackageManager.NameNotFoundException e) { 1407 // Default to old behavior if we can not find this. 1408 targetSdk = -1; 1409 } 1410 return targetSdk; 1411 } 1412 getITelephony()1413 private static ITelephony getITelephony() { 1414 ITelephony binder = ITelephony.Stub.asInterface( 1415 ServiceManager.getService(Context.TELEPHONY_SERVICE)); 1416 if (binder == null) { 1417 throw new RuntimeException("Could not find Telephony Service."); 1418 } 1419 return binder; 1420 } 1421 notifySmsErrorNoDefaultSet(Context context, PendingIntent pendingIntent)1422 private static void notifySmsErrorNoDefaultSet(Context context, PendingIntent pendingIntent) { 1423 if (pendingIntent != null) { 1424 Intent errorMessage = new Intent(); 1425 errorMessage.putExtra(NO_DEFAULT_EXTRA, true); 1426 try { 1427 pendingIntent.send(context, RESULT_ERROR_GENERIC_FAILURE, errorMessage); 1428 } catch (PendingIntent.CanceledException e) { 1429 // Don't worry about it, we do not need to notify the caller if this is the case. 1430 } 1431 } 1432 } 1433 notifySmsErrorNoDefaultSet(Context context, List<PendingIntent> pendingIntents)1434 private static void notifySmsErrorNoDefaultSet(Context context, 1435 List<PendingIntent> pendingIntents) { 1436 if (pendingIntents != null) { 1437 for (PendingIntent pendingIntent : pendingIntents) { 1438 Intent errorMessage = new Intent(); 1439 errorMessage.putExtra(NO_DEFAULT_EXTRA, true); 1440 try { 1441 pendingIntent.send(context, RESULT_ERROR_GENERIC_FAILURE, errorMessage); 1442 } catch (PendingIntent.CanceledException e) { 1443 // Don't worry about it, we do not need to notify the caller if this is the 1444 // case. 1445 } 1446 } 1447 } 1448 } 1449 notifySmsGenericError(PendingIntent pendingIntent)1450 private static void notifySmsGenericError(PendingIntent pendingIntent) { 1451 if (pendingIntent != null) { 1452 try { 1453 pendingIntent.send(RESULT_ERROR_GENERIC_FAILURE); 1454 } catch (PendingIntent.CanceledException e) { 1455 // Don't worry about it, we do not need to notify the caller if this is the case. 1456 } 1457 } 1458 } 1459 notifySmsGenericError(List<PendingIntent> pendingIntents)1460 private static void notifySmsGenericError(List<PendingIntent> pendingIntents) { 1461 if (pendingIntents != null) { 1462 for (PendingIntent pendingIntent : pendingIntents) { 1463 try { 1464 pendingIntent.send(RESULT_ERROR_GENERIC_FAILURE); 1465 } catch (PendingIntent.CanceledException e) { 1466 // Don't worry about it, we do not need to notify the caller if this is the 1467 // case. 1468 } 1469 } 1470 } 1471 } 1472 1473 /** 1474 * Returns the ISms service, or throws an UnsupportedOperationException if 1475 * the service does not exist. 1476 */ getISmsServiceOrThrow()1477 private static ISms getISmsServiceOrThrow() { 1478 ISms iSms = getISmsService(); 1479 if (iSms == null) { 1480 throw new UnsupportedOperationException("Sms is not supported"); 1481 } 1482 return iSms; 1483 } 1484 getISmsService()1485 private static ISms getISmsService() { 1486 return ISms.Stub.asInterface(ServiceManager.getService("isms")); 1487 } 1488 1489 /** 1490 * Copy a raw SMS PDU to the ICC. 1491 * ICC (Integrated Circuit Card) is the card of the device. 1492 * For example, this can be the SIM or USIM for GSM. 1493 * 1494 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1495 * applications or the Telephony framework and will never trigger an SMS disambiguation 1496 * dialog. If this method is called on a device that has multiple active subscriptions, this 1497 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1498 * default subscription is defined, the subscription ID associated with this message will be 1499 * INVALID, which will result in the operation being completed on the subscription associated 1500 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1501 * operation is performed on the correct subscription. 1502 * </p> 1503 * 1504 * @param smsc the SMSC for this message, or NULL for the default SMSC 1505 * @param pdu the raw PDU to store 1506 * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, 1507 * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) 1508 * @return true for success 1509 * 1510 * @throws IllegalArgumentException if pdu is NULL 1511 * {@hide} 1512 */ 1513 @UnsupportedAppUsage copyMessageToIcc(byte[] smsc, byte[] pdu,int status)1514 public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) { 1515 boolean success = false; 1516 1517 if (null == pdu) { 1518 throw new IllegalArgumentException("pdu is NULL"); 1519 } 1520 try { 1521 ISms iSms = getISmsService(); 1522 if (iSms != null) { 1523 success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(), 1524 ActivityThread.currentPackageName(), 1525 status, pdu, smsc); 1526 } 1527 } catch (RemoteException ex) { 1528 // ignore it 1529 } 1530 1531 return success; 1532 } 1533 1534 /** 1535 * Delete the specified message from the ICC. 1536 * ICC (Integrated Circuit Card) is the card of the device. 1537 * For example, this can be the SIM or USIM for GSM. 1538 * 1539 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1540 * applications or the Telephony framework and will never trigger an SMS disambiguation 1541 * dialog. If this method is called on a device that has multiple active subscriptions, this 1542 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1543 * default subscription is defined, the subscription ID associated with this message will be 1544 * INVALID, which will result in the operation being completed on the subscription associated 1545 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1546 * operation is performed on the correct subscription. 1547 * </p> 1548 * 1549 * @param messageIndex is the record index of the message on ICC 1550 * @return true for success 1551 * 1552 * {@hide} 1553 */ 1554 @UnsupportedAppUsage 1555 public boolean deleteMessageFromIcc(int messageIndex)1556 deleteMessageFromIcc(int messageIndex) { 1557 boolean success = false; 1558 byte[] pdu = new byte[SMS_RECORD_LENGTH-1]; 1559 Arrays.fill(pdu, (byte)0xff); 1560 1561 try { 1562 ISms iSms = getISmsService(); 1563 if (iSms != null) { 1564 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(), 1565 ActivityThread.currentPackageName(), 1566 messageIndex, STATUS_ON_ICC_FREE, pdu); 1567 } 1568 } catch (RemoteException ex) { 1569 // ignore it 1570 } 1571 1572 return success; 1573 } 1574 1575 /** 1576 * Update the specified message on the ICC. 1577 * ICC (Integrated Circuit Card) is the card of the device. 1578 * For example, this can be the SIM or USIM for GSM. 1579 * 1580 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1581 * applications or the Telephony framework and will never trigger an SMS disambiguation 1582 * dialog. If this method is called on a device that has multiple active subscriptions, this 1583 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1584 * default subscription is defined, the subscription ID associated with this message will be 1585 * INVALID, which will result in the operation being completed on the subscription associated 1586 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1587 * operation is performed on the correct subscription. 1588 * </p> 1589 * 1590 * @param messageIndex record index of message to update 1591 * @param newStatus new message status (STATUS_ON_ICC_READ, 1592 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 1593 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 1594 * @param pdu the raw PDU to store 1595 * @return true for success 1596 * 1597 * {@hide} 1598 */ 1599 @UnsupportedAppUsage updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu)1600 public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { 1601 boolean success = false; 1602 1603 try { 1604 ISms iSms = getISmsService(); 1605 if (iSms != null) { 1606 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(), 1607 ActivityThread.currentPackageName(), 1608 messageIndex, newStatus, pdu); 1609 } 1610 } catch (RemoteException ex) { 1611 // ignore it 1612 } 1613 1614 return success; 1615 } 1616 1617 /** 1618 * Retrieves all messages currently stored on ICC. 1619 * ICC (Integrated Circuit Card) is the card of the device. 1620 * For example, this can be the SIM or USIM for GSM. 1621 * 1622 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1623 * applications or the Telephony framework and will never trigger an SMS disambiguation 1624 * dialog. If this method is called on a device that has multiple active subscriptions, this 1625 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1626 * default subscription is defined, the subscription ID associated with this message will be 1627 * INVALID, which will result in the operation being completed on the subscription associated 1628 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1629 * operation is performed on the correct subscription. 1630 * </p> 1631 * 1632 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects 1633 * 1634 * {@hide} 1635 */ 1636 @UnsupportedAppUsage getAllMessagesFromIcc()1637 public ArrayList<SmsMessage> getAllMessagesFromIcc() { 1638 List<SmsRawData> records = null; 1639 1640 try { 1641 ISms iSms = getISmsService(); 1642 if (iSms != null) { 1643 records = iSms.getAllMessagesFromIccEfForSubscriber( 1644 getSubscriptionId(), 1645 ActivityThread.currentPackageName()); 1646 } 1647 } catch (RemoteException ex) { 1648 // ignore it 1649 } 1650 1651 return createMessageListFromRawRecords(records); 1652 } 1653 1654 /** 1655 * Enable reception of cell broadcast (SMS-CB) messages with the given 1656 * message identifier and RAN type. The RAN type specify this message ID 1657 * belong to 3GPP (GSM) or 3GPP2(CDMA).Note that if two different clients 1658 * enable the same message identifier, they must both disable it for the device to stop 1659 * receiving those messages. All received messages will be broadcast in an 1660 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 1661 * Note: This call is blocking, callers may want to avoid calling it from 1662 * the main thread of an application. 1663 * 1664 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1665 * applications or the Telephony framework and will never trigger an SMS disambiguation 1666 * dialog. If this method is called on a device that has multiple active subscriptions, this 1667 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1668 * default subscription is defined, the subscription ID associated with this message will be 1669 * INVALID, which will result in the operation being completed on the subscription associated 1670 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1671 * operation is performed on the correct subscription. 1672 * </p> 1673 * 1674 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 1675 * or C.R1001-G (3GPP2) 1676 * @param ranType as defined in class SmsManager, the value can be one of these: 1677 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM 1678 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA 1679 * @return true if successful, false otherwise 1680 * @see #disableCellBroadcast(int, int) 1681 * 1682 * {@hide} 1683 */ enableCellBroadcast(int messageIdentifier, int ranType)1684 public boolean enableCellBroadcast(int messageIdentifier, int ranType) { 1685 boolean success = false; 1686 1687 try { 1688 ISms iSms = getISmsService(); 1689 if (iSms != null) { 1690 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use 1691 // the default phone internally. 1692 success = iSms.enableCellBroadcastForSubscriber(getSubscriptionId(), 1693 messageIdentifier, ranType); 1694 } 1695 } catch (RemoteException ex) { 1696 // ignore it 1697 } 1698 1699 return success; 1700 } 1701 1702 /** 1703 * Disable reception of cell broadcast (SMS-CB) messages with the given 1704 * message identifier and RAN type. The RAN type specify this message ID 1705 * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients 1706 * enable the same message identifier, they must both disable it for the 1707 * device to stop receiving those messages. 1708 * Note: This call is blocking, callers may want to avoid calling it from 1709 * the main thread of an application. 1710 * 1711 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1712 * applications or the Telephony framework and will never trigger an SMS disambiguation 1713 * dialog. If this method is called on a device that has multiple active subscriptions, this 1714 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1715 * default subscription is defined, the subscription ID associated with this message will be 1716 * INVALID, which will result in the operation being completed on the subscription associated 1717 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1718 * operation is performed on the correct subscription. 1719 * </p> 1720 * 1721 * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) 1722 * or C.R1001-G (3GPP2) 1723 * @param ranType as defined in class SmsManager, the value can be one of these: 1724 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM 1725 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA 1726 * @return true if successful, false otherwise 1727 * 1728 * @see #enableCellBroadcast(int, int) 1729 * 1730 * {@hide} 1731 */ disableCellBroadcast(int messageIdentifier, int ranType)1732 public boolean disableCellBroadcast(int messageIdentifier, int ranType) { 1733 boolean success = false; 1734 1735 try { 1736 ISms iSms = getISmsService(); 1737 if (iSms != null) { 1738 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use 1739 // the default phone internally. 1740 success = iSms.disableCellBroadcastForSubscriber(getSubscriptionId(), 1741 messageIdentifier, ranType); 1742 } 1743 } catch (RemoteException ex) { 1744 // ignore it 1745 } 1746 1747 return success; 1748 } 1749 1750 /** 1751 * Enable reception of cell broadcast (SMS-CB) messages with the given 1752 * message identifier range and RAN type. The RAN type specify this message ID 1753 * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable 1754 * the same message identifier, they must both disable it for the device to stop 1755 * receiving those messages. All received messages will be broadcast in an 1756 * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". 1757 * Note: This call is blocking, callers may want to avoid calling it from 1758 * the main thread of an application. 1759 * 1760 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1761 * applications or the Telephony framework and will never trigger an SMS disambiguation 1762 * dialog. If this method is called on a device that has multiple active subscriptions, this 1763 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1764 * default subscription is defined, the subscription ID associated with this message will be 1765 * INVALID, which will result in the operation being completed on the subscription associated 1766 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1767 * operation is performed on the correct subscription. 1768 * </p> 1769 * 1770 * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) 1771 * or C.R1001-G (3GPP2) 1772 * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) 1773 * or C.R1001-G (3GPP2) 1774 * @param ranType as defined in class SmsManager, the value can be one of these: 1775 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM 1776 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA 1777 * @return true if successful, false otherwise 1778 * @see #disableCellBroadcastRange(int, int, int) 1779 * 1780 * @throws IllegalArgumentException if endMessageId < startMessageId 1781 * {@hide} 1782 */ 1783 @UnsupportedAppUsage enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)1784 public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) { 1785 boolean success = false; 1786 1787 if (endMessageId < startMessageId) { 1788 throw new IllegalArgumentException("endMessageId < startMessageId"); 1789 } 1790 try { 1791 ISms iSms = getISmsService(); 1792 if (iSms != null) { 1793 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use 1794 // the default phone internally. 1795 success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(), 1796 startMessageId, endMessageId, ranType); 1797 } 1798 } catch (RemoteException ex) { 1799 // ignore it 1800 } 1801 1802 return success; 1803 } 1804 1805 /** 1806 * Disable reception of cell broadcast (SMS-CB) messages with the given 1807 * message identifier range and RAN type. The RAN type specify this message 1808 * ID range belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different 1809 * clients enable the same message identifier, they must both disable it for 1810 * the device to stop receiving those messages. 1811 * Note: This call is blocking, callers may want to avoid calling it from 1812 * the main thread of an application. 1813 * 1814 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1815 * applications or the Telephony framework and will never trigger an SMS disambiguation 1816 * dialog. If this method is called on a device that has multiple active subscriptions, this 1817 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1818 * default subscription is defined, the subscription ID associated with this message will be 1819 * INVALID, which will result in the operation being completed on the subscription associated 1820 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1821 * operation is performed on the correct subscription. 1822 * </p> 1823 * 1824 * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) 1825 * or C.R1001-G (3GPP2) 1826 * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) 1827 * or C.R1001-G (3GPP2) 1828 * @param ranType as defined in class SmsManager, the value can be one of these: 1829 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM 1830 * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA 1831 * @return true if successful, false otherwise 1832 * 1833 * @see #enableCellBroadcastRange(int, int, int) 1834 * 1835 * @throws IllegalArgumentException if endMessageId < startMessageId 1836 * {@hide} 1837 */ 1838 @UnsupportedAppUsage disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)1839 public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) { 1840 boolean success = false; 1841 1842 if (endMessageId < startMessageId) { 1843 throw new IllegalArgumentException("endMessageId < startMessageId"); 1844 } 1845 try { 1846 ISms iSms = getISmsService(); 1847 if (iSms != null) { 1848 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use 1849 // the default phone internally. 1850 success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(), 1851 startMessageId, endMessageId, ranType); 1852 } 1853 } catch (RemoteException ex) { 1854 // ignore it 1855 } 1856 1857 return success; 1858 } 1859 1860 /** 1861 * Create a list of <code>SmsMessage</code>s from a list of RawSmsData 1862 * records returned by <code>getAllMessagesFromIcc()</code> 1863 * 1864 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1865 * applications or the Telephony framework and will never trigger an SMS disambiguation 1866 * dialog. If this method is called on a device that has multiple active subscriptions, this 1867 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1868 * default subscription is defined, the subscription ID associated with this message will be 1869 * INVALID, which will result in the operation being completed on the subscription associated 1870 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1871 * operation is performed on the correct subscription. 1872 * </p> 1873 * 1874 * @param records SMS EF records, returned by 1875 * <code>getAllMessagesFromIcc</code> 1876 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. 1877 */ createMessageListFromRawRecords(List<SmsRawData> records)1878 private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { 1879 ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); 1880 if (records != null) { 1881 int count = records.size(); 1882 for (int i = 0; i < count; i++) { 1883 SmsRawData data = records.get(i); 1884 // List contains all records, including "free" records (null) 1885 if (data != null) { 1886 SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes(), 1887 getSubscriptionId()); 1888 if (sms != null) { 1889 messages.add(sms); 1890 } 1891 } 1892 } 1893 } 1894 return messages; 1895 } 1896 1897 /** 1898 * SMS over IMS is supported if IMS is registered and SMS is supported 1899 * on IMS. 1900 * 1901 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1902 * applications or the Telephony framework and will never trigger an SMS disambiguation 1903 * dialog. If this method is called on a device that has multiple active subscriptions, this 1904 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1905 * default subscription is defined, the subscription ID associated with this message will be 1906 * INVALID, which will result in the operation being completed on the subscription associated 1907 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1908 * operation is performed on the correct subscription. 1909 * </p> 1910 * 1911 * @return true if SMS over IMS is supported, false otherwise 1912 * 1913 * @see #getImsSmsFormat() 1914 * 1915 * @hide 1916 */ isImsSmsSupported()1917 public boolean isImsSmsSupported() { 1918 boolean boSupported = false; 1919 try { 1920 ISms iSms = getISmsService(); 1921 if (iSms != null) { 1922 boSupported = iSms.isImsSmsSupportedForSubscriber(getSubscriptionId()); 1923 } 1924 } catch (RemoteException ex) { 1925 // ignore it 1926 } 1927 return boSupported; 1928 } 1929 1930 /** 1931 * Gets SMS format supported on IMS. SMS over IMS format is either 3GPP or 3GPP2. 1932 * 1933 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 1934 * applications or the Telephony framework and will never trigger an SMS disambiguation 1935 * dialog. If this method is called on a device that has multiple active subscriptions, this 1936 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 1937 * default subscription is defined, the subscription ID associated with this message will be 1938 * INVALID, which will result in the operation being completed on the subscription associated 1939 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 1940 * operation is performed on the correct subscription. 1941 * </p> 1942 * 1943 * @return SmsMessage.FORMAT_3GPP, 1944 * SmsMessage.FORMAT_3GPP2 1945 * or SmsMessage.FORMAT_UNKNOWN 1946 * 1947 * @see #isImsSmsSupported() 1948 * 1949 * @hide 1950 */ getImsSmsFormat()1951 public String getImsSmsFormat() { 1952 String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN; 1953 try { 1954 ISms iSms = getISmsService(); 1955 if (iSms != null) { 1956 format = iSms.getImsSmsFormatForSubscriber(getSubscriptionId()); 1957 } 1958 } catch (RemoteException ex) { 1959 // ignore it 1960 } 1961 return format; 1962 } 1963 1964 /** 1965 * Get default sms subscription id. 1966 * 1967 * <p class="note"><strong>Note:</strong>This returns a value different from 1968 * {@link SubscriptionManager#getDefaultSmsSubscriptionId} if the user has not chosen a default. 1969 * In this case it returns the active subscription id if there's only one active subscription 1970 * available. 1971 * 1972 * @return the user-defined default SMS subscription id, or the active subscription id if 1973 * there's only one active subscription available, otherwise 1974 * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. 1975 */ getDefaultSmsSubscriptionId()1976 public static int getDefaultSmsSubscriptionId() { 1977 try { 1978 return getISmsService().getPreferredSmsSubscription(); 1979 } catch (RemoteException e) { 1980 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 1981 } catch (NullPointerException e) { 1982 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 1983 } 1984 } 1985 1986 /** 1987 * Get SMS prompt property, enabled or not 1988 * 1989 * @return true if enabled, false otherwise 1990 * @hide 1991 */ 1992 @UnsupportedAppUsage isSMSPromptEnabled()1993 public boolean isSMSPromptEnabled() { 1994 ISms iSms = null; 1995 try { 1996 iSms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 1997 return iSms.isSMSPromptEnabled(); 1998 } catch (RemoteException ex) { 1999 return false; 2000 } catch (NullPointerException ex) { 2001 return false; 2002 } 2003 } 2004 2005 // see SmsMessage.getStatusOnIcc 2006 2007 /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 2008 static public final int STATUS_ON_ICC_FREE = 0; 2009 2010 /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 2011 static public final int STATUS_ON_ICC_READ = 1; 2012 2013 /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 2014 static public final int STATUS_ON_ICC_UNREAD = 3; 2015 2016 /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 2017 static public final int STATUS_ON_ICC_SENT = 5; 2018 2019 /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 2020 static public final int STATUS_ON_ICC_UNSENT = 7; 2021 2022 // SMS send failure result codes 2023 2024 /** 2025 * No error. 2026 * @hide 2027 */ 2028 @SystemApi 2029 static public final int RESULT_ERROR_NONE = 0; 2030 /** Generic failure cause */ 2031 static public final int RESULT_ERROR_GENERIC_FAILURE = 1; 2032 /** Failed because radio was explicitly turned off */ 2033 static public final int RESULT_ERROR_RADIO_OFF = 2; 2034 /** Failed because no pdu provided */ 2035 static public final int RESULT_ERROR_NULL_PDU = 3; 2036 /** Failed because service is currently unavailable */ 2037 static public final int RESULT_ERROR_NO_SERVICE = 4; 2038 /** Failed because we reached the sending queue limit. */ 2039 static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5; 2040 /** 2041 * Failed because FDN is enabled. 2042 * @hide 2043 */ 2044 @SystemApi 2045 static public final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; 2046 /** Failed because user denied the sending of this short code. */ 2047 static public final int RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7; 2048 /** Failed because the user has denied this app ever send premium short codes. */ 2049 static public final int RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8; 2050 /** 2051 * Failed because the radio was not available 2052 * @hide 2053 */ 2054 @SystemApi 2055 static public final int RESULT_RADIO_NOT_AVAILABLE = 9; 2056 /** 2057 * Failed because of network rejection 2058 * @hide 2059 */ 2060 @SystemApi 2061 static public final int RESULT_NETWORK_REJECT = 10; 2062 /** 2063 * Failed because of invalid arguments 2064 * @hide 2065 */ 2066 @SystemApi 2067 static public final int RESULT_INVALID_ARGUMENTS = 11; 2068 /** 2069 * Failed because of an invalid state 2070 * @hide 2071 */ 2072 @SystemApi 2073 static public final int RESULT_INVALID_STATE = 12; 2074 /** 2075 * Failed because there is no memory 2076 * @hide 2077 */ 2078 @SystemApi 2079 static public final int RESULT_NO_MEMORY = 13; 2080 /** 2081 * Failed because the sms format is not valid 2082 * @hide 2083 */ 2084 @SystemApi 2085 static public final int RESULT_INVALID_SMS_FORMAT = 14; 2086 /** 2087 * Failed because of a system error 2088 * @hide 2089 */ 2090 @SystemApi 2091 static public final int RESULT_SYSTEM_ERROR = 15; 2092 /** 2093 * Failed because of a modem error 2094 * @hide 2095 */ 2096 @SystemApi 2097 static public final int RESULT_MODEM_ERROR = 16; 2098 /** 2099 * Failed because of a network error 2100 * @hide 2101 */ 2102 @SystemApi 2103 static public final int RESULT_NETWORK_ERROR = 17; 2104 /** 2105 * Failed because of an encoding error 2106 * @hide 2107 */ 2108 @SystemApi 2109 static public final int RESULT_ENCODING_ERROR = 18; 2110 /** 2111 * Failed because of an invalid smsc address 2112 * @hide 2113 */ 2114 @SystemApi 2115 static public final int RESULT_INVALID_SMSC_ADDRESS = 19; 2116 /** 2117 * Failed because the operation is not allowed 2118 * @hide 2119 */ 2120 @SystemApi 2121 static public final int RESULT_OPERATION_NOT_ALLOWED = 20; 2122 /** 2123 * Failed because of an internal error 2124 * @hide 2125 */ 2126 @SystemApi 2127 static public final int RESULT_INTERNAL_ERROR = 21; 2128 /** 2129 * Failed because there are no resources 2130 * @hide 2131 */ 2132 @SystemApi 2133 static public final int RESULT_NO_RESOURCES = 22; 2134 /** 2135 * Failed because the operation was cancelled 2136 * @hide 2137 */ 2138 @SystemApi 2139 static public final int RESULT_CANCELLED = 23; 2140 /** 2141 * Failed because the request is not supported 2142 * @hide 2143 */ 2144 @SystemApi 2145 static public final int RESULT_REQUEST_NOT_SUPPORTED = 24; 2146 2147 2148 static private final String PHONE_PACKAGE_NAME = "com.android.phone"; 2149 2150 /** 2151 * Send an MMS message 2152 * 2153 * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation 2154 * dialog. If this method is called on a device that has multiple active subscriptions, this 2155 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 2156 * default subscription is defined, the subscription ID associated with this message will be 2157 * INVALID, which will result in the operation being completed on the subscription associated 2158 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 2159 * operation is performed on the correct subscription. 2160 * </p> 2161 * 2162 * @param context application context 2163 * @param contentUri the content Uri from which the message pdu will be read 2164 * @param locationUrl the optional location url where message should be sent to 2165 * @param configOverrides the carrier-specific messaging configuration values to override for 2166 * sending the message. 2167 * @param sentIntent if not NULL this <code>PendingIntent</code> is 2168 * broadcast when the message is successfully sent, or failed 2169 * @throws IllegalArgumentException if contentUri is empty 2170 */ sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent)2171 public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, 2172 Bundle configOverrides, PendingIntent sentIntent) { 2173 if (contentUri == null) { 2174 throw new IllegalArgumentException("Uri contentUri null"); 2175 } 2176 try { 2177 final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2178 if (iMms == null) { 2179 return; 2180 } 2181 2182 iMms.sendMessage(getSubscriptionId(), ActivityThread.currentPackageName(), contentUri, 2183 locationUrl, configOverrides, sentIntent); 2184 } catch (RemoteException e) { 2185 // Ignore it 2186 } 2187 } 2188 2189 /** 2190 * Download an MMS message from carrier by a given location URL 2191 * 2192 * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation 2193 * dialog. If this method is called on a device that has multiple active subscriptions, this 2194 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 2195 * default subscription is defined, the subscription ID associated with this message will be 2196 * INVALID, which will result in the operation being completed on the subscription associated 2197 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 2198 * operation is performed on the correct subscription. 2199 * </p> 2200 * 2201 * @param context application context 2202 * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained 2203 * from the MMS WAP push notification 2204 * @param contentUri the content uri to which the downloaded pdu will be written 2205 * @param configOverrides the carrier-specific messaging configuration values to override for 2206 * downloading the message. 2207 * @param downloadedIntent if not NULL this <code>PendingIntent</code> is 2208 * broadcast when the message is downloaded, or the download is failed 2209 * @throws IllegalArgumentException if locationUrl or contentUri is empty 2210 */ downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent)2211 public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, 2212 Bundle configOverrides, PendingIntent downloadedIntent) { 2213 if (TextUtils.isEmpty(locationUrl)) { 2214 throw new IllegalArgumentException("Empty MMS location URL"); 2215 } 2216 if (contentUri == null) { 2217 throw new IllegalArgumentException("Uri contentUri null"); 2218 } 2219 try { 2220 final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2221 if (iMms == null) { 2222 return; 2223 } 2224 iMms.downloadMessage(getSubscriptionId(), ActivityThread.currentPackageName(), 2225 locationUrl, contentUri, configOverrides, downloadedIntent); 2226 } catch (RemoteException e) { 2227 // Ignore it 2228 } 2229 } 2230 2231 // MMS send/download failure result codes 2232 public static final int MMS_ERROR_UNSPECIFIED = 1; 2233 public static final int MMS_ERROR_INVALID_APN = 2; 2234 public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; 2235 public static final int MMS_ERROR_HTTP_FAILURE = 4; 2236 public static final int MMS_ERROR_IO_ERROR = 5; 2237 public static final int MMS_ERROR_RETRY = 6; 2238 public static final int MMS_ERROR_CONFIGURATION_ERROR = 7; 2239 public static final int MMS_ERROR_NO_DATA_NETWORK = 8; 2240 2241 /** Intent extra name for MMS sending result data in byte array type */ 2242 public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA"; 2243 /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */ 2244 public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS"; 2245 2246 /** 2247 * Import a text message into system's SMS store 2248 * 2249 * Only default SMS apps can import SMS 2250 * 2251 * @param address the destination(source) address of the sent(received) message 2252 * @param type the type of the message 2253 * @param text the message text 2254 * @param timestampMillis the message timestamp in milliseconds 2255 * @param seen if the message is seen 2256 * @param read if the message is read 2257 * @return the message URI, null if failed 2258 * @hide 2259 */ importTextMessage(String address, int type, String text, long timestampMillis, boolean seen, boolean read)2260 public Uri importTextMessage(String address, int type, String text, long timestampMillis, 2261 boolean seen, boolean read) { 2262 try { 2263 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2264 if (iMms != null) { 2265 return iMms.importTextMessage(ActivityThread.currentPackageName(), 2266 address, type, text, timestampMillis, seen, read); 2267 } 2268 } catch (RemoteException ex) { 2269 // ignore it 2270 } 2271 return null; 2272 } 2273 2274 /** Represents the received SMS message for importing {@hide} */ 2275 public static final int SMS_TYPE_INCOMING = 0; 2276 /** Represents the sent SMS message for importing {@hide} */ 2277 public static final int SMS_TYPE_OUTGOING = 1; 2278 2279 /** 2280 * Import a multimedia message into system's MMS store. Only the following PDU type is 2281 * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind 2282 * 2283 * Only default SMS apps can import MMS 2284 * 2285 * @param contentUri the content uri from which to read the PDU of the message to import 2286 * @param messageId the optional message id. Use null if not specifying 2287 * @param timestampSecs the optional message timestamp. Use -1 if not specifying 2288 * @param seen if the message is seen 2289 * @param read if the message is read 2290 * @return the message URI, null if failed 2291 * @throws IllegalArgumentException if pdu is empty 2292 * {@hide} 2293 */ importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs, boolean seen, boolean read)2294 public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs, 2295 boolean seen, boolean read) { 2296 if (contentUri == null) { 2297 throw new IllegalArgumentException("Uri contentUri null"); 2298 } 2299 try { 2300 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2301 if (iMms != null) { 2302 return iMms.importMultimediaMessage(ActivityThread.currentPackageName(), 2303 contentUri, messageId, timestampSecs, seen, read); 2304 } 2305 } catch (RemoteException ex) { 2306 // ignore it 2307 } 2308 return null; 2309 } 2310 2311 /** 2312 * Delete a system stored SMS or MMS message 2313 * 2314 * Only default SMS apps can delete system stored SMS and MMS messages 2315 * 2316 * @param messageUri the URI of the stored message 2317 * @return true if deletion is successful, false otherwise 2318 * @throws IllegalArgumentException if messageUri is empty 2319 * {@hide} 2320 */ deleteStoredMessage(Uri messageUri)2321 public boolean deleteStoredMessage(Uri messageUri) { 2322 if (messageUri == null) { 2323 throw new IllegalArgumentException("Empty message URI"); 2324 } 2325 try { 2326 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2327 if (iMms != null) { 2328 return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri); 2329 } 2330 } catch (RemoteException ex) { 2331 // ignore it 2332 } 2333 return false; 2334 } 2335 2336 /** 2337 * Delete a system stored SMS or MMS thread 2338 * 2339 * Only default SMS apps can delete system stored SMS and MMS conversations 2340 * 2341 * @param conversationId the ID of the message conversation 2342 * @return true if deletion is successful, false otherwise 2343 * {@hide} 2344 */ deleteStoredConversation(long conversationId)2345 public boolean deleteStoredConversation(long conversationId) { 2346 try { 2347 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2348 if (iMms != null) { 2349 return iMms.deleteStoredConversation( 2350 ActivityThread.currentPackageName(), conversationId); 2351 } 2352 } catch (RemoteException ex) { 2353 // ignore it 2354 } 2355 return false; 2356 } 2357 2358 /** 2359 * Update the status properties of a system stored SMS or MMS message, e.g. 2360 * the read status of a message, etc. 2361 * 2362 * @param messageUri the URI of the stored message 2363 * @param statusValues a list of status properties in key-value pairs to update 2364 * @return true if update is successful, false otherwise 2365 * @throws IllegalArgumentException if messageUri is empty 2366 * {@hide} 2367 */ updateStoredMessageStatus(Uri messageUri, ContentValues statusValues)2368 public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) { 2369 if (messageUri == null) { 2370 throw new IllegalArgumentException("Empty message URI"); 2371 } 2372 try { 2373 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2374 if (iMms != null) { 2375 return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(), 2376 messageUri, statusValues); 2377 } 2378 } catch (RemoteException ex) { 2379 // ignore it 2380 } 2381 return false; 2382 } 2383 2384 /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */ 2385 public static final String MESSAGE_STATUS_SEEN = "seen"; 2386 /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */ 2387 public static final String MESSAGE_STATUS_READ = "read"; 2388 2389 /** 2390 * Archive or unarchive a stored conversation 2391 * 2392 * @param conversationId the ID of the message conversation 2393 * @param archived true to archive the conversation, false to unarchive 2394 * @return true if update is successful, false otherwise 2395 * {@hide} 2396 */ archiveStoredConversation(long conversationId, boolean archived)2397 public boolean archiveStoredConversation(long conversationId, boolean archived) { 2398 try { 2399 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2400 if (iMms != null) { 2401 return iMms.archiveStoredConversation(ActivityThread.currentPackageName(), 2402 conversationId, archived); 2403 } 2404 } catch (RemoteException ex) { 2405 // ignore it 2406 } 2407 return false; 2408 } 2409 2410 /** 2411 * Add a text message draft to system SMS store 2412 * 2413 * Only default SMS apps can add SMS draft 2414 * 2415 * @param address the destination address of message 2416 * @param text the body of the message to send 2417 * @return the URI of the stored draft message 2418 * {@hide} 2419 */ addTextMessageDraft(String address, String text)2420 public Uri addTextMessageDraft(String address, String text) { 2421 try { 2422 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2423 if (iMms != null) { 2424 return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text); 2425 } 2426 } catch (RemoteException ex) { 2427 // ignore it 2428 } 2429 return null; 2430 } 2431 2432 /** 2433 * Add a multimedia message draft to system MMS store 2434 * 2435 * Only default SMS apps can add MMS draft 2436 * 2437 * @param contentUri the content uri from which to read the PDU data of the draft MMS 2438 * @return the URI of the stored draft message 2439 * @throws IllegalArgumentException if pdu is empty 2440 * {@hide} 2441 */ addMultimediaMessageDraft(Uri contentUri)2442 public Uri addMultimediaMessageDraft(Uri contentUri) { 2443 if (contentUri == null) { 2444 throw new IllegalArgumentException("Uri contentUri null"); 2445 } 2446 try { 2447 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2448 if (iMms != null) { 2449 return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(), 2450 contentUri); 2451 } 2452 } catch (RemoteException ex) { 2453 // ignore it 2454 } 2455 return null; 2456 } 2457 2458 /** 2459 * Send a system stored text message. 2460 * 2461 * You can only send a failed text message or a draft text message. 2462 * 2463 * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this 2464 * manager on a multi-SIM device, this operation may fail sending the SMS message because no 2465 * suitable default subscription could be found. In this case, if {@code sentIntent} is 2466 * non-null, then the {@link PendingIntent} will be sent with an error code 2467 * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the 2468 * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions 2469 * where this operation may fail. 2470 * </p> 2471 * 2472 * @param messageUri the URI of the stored message 2473 * @param scAddress is the service center address or null to use the current default SMSC 2474 * @param sentIntent if not NULL this <code>PendingIntent</code> is 2475 * broadcast when the message is successfully sent, or failed. 2476 * The result code will be <code>Activity.RESULT_OK</code> for success, 2477 * or one of these errors:<br> 2478 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 2479 * <code>RESULT_ERROR_RADIO_OFF</code><br> 2480 * <code>RESULT_ERROR_NULL_PDU</code><br> 2481 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 2482 * the extra "errorCode" containing a radio technology specific value, 2483 * generally only useful for troubleshooting.<br> 2484 * The per-application based SMS control checks sentIntent. If sentIntent 2485 * is NULL the caller will be checked against all unknown applications, 2486 * which cause smaller number of SMS to be sent in checking period. 2487 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 2488 * broadcast when the message is delivered to the recipient. The 2489 * raw pdu of the status report is in the extended data ("pdu"). 2490 * 2491 * @throws IllegalArgumentException if messageUri is empty 2492 * {@hide} 2493 */ sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)2494 public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent, 2495 PendingIntent deliveryIntent) { 2496 if (messageUri == null) { 2497 throw new IllegalArgumentException("Empty message URI"); 2498 } 2499 final Context context = ActivityThread.currentApplication().getApplicationContext(); 2500 resolveSubscriptionForOperation(new SubscriptionResolverResult() { 2501 @Override 2502 public void onSuccess(int subId) { 2503 try { 2504 ISms iSms = getISmsServiceOrThrow(); 2505 iSms.sendStoredText(subId, ActivityThread.currentPackageName(), messageUri, 2506 scAddress, sentIntent, deliveryIntent); 2507 } catch (RemoteException e) { 2508 Log.e(TAG, "sendStoredTextMessage: Couldn't send SMS - Exception: " 2509 + e.getMessage()); 2510 notifySmsGenericError(sentIntent); 2511 } 2512 } 2513 @Override 2514 public void onFailure() { 2515 notifySmsErrorNoDefaultSet(context, sentIntent); 2516 } 2517 }); 2518 } 2519 2520 /** 2521 * Send a system stored multi-part text message. 2522 * 2523 * You can only send a failed text message or a draft text message. 2524 * The provided <code>PendingIntent</code> lists should match the part number of the 2525 * divided text of the stored message by using <code>divideMessage</code> 2526 * 2527 * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this 2528 * manager on a multi-SIM device, this operation may fail sending the SMS message because no 2529 * suitable default subscription could be found. In this case, if {@code sentIntent} is 2530 * non-null, then the {@link PendingIntent} will be sent with an error code 2531 * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the 2532 * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions 2533 * where this operation may fail. 2534 * </p> 2535 * 2536 * @param messageUri the URI of the stored message 2537 * @param scAddress is the service center address or null to use 2538 * the current default SMSC 2539 * @param sentIntents if not null, an <code>ArrayList</code> of 2540 * <code>PendingIntent</code>s (one for each message part) that is 2541 * broadcast when the corresponding message part has been sent. 2542 * The result code will be <code>Activity.RESULT_OK</code> for success, 2543 * or one of these errors:<br> 2544 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 2545 * <code>RESULT_ERROR_RADIO_OFF</code><br> 2546 * <code>RESULT_ERROR_NULL_PDU</code><br> 2547 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include 2548 * the extra "errorCode" containing a radio technology specific value, 2549 * generally only useful for troubleshooting.<br> 2550 * The per-application based SMS control checks sentIntent. If sentIntent 2551 * is NULL the caller will be checked against all unknown applications, 2552 * which cause smaller number of SMS to be sent in checking period. 2553 * @param deliveryIntents if not null, an <code>ArrayList</code> of 2554 * <code>PendingIntent</code>s (one for each message part) that is 2555 * broadcast when the corresponding message part has been delivered 2556 * to the recipient. The raw pdu of the status report is in the 2557 * extended data ("pdu"). 2558 * 2559 * @throws IllegalArgumentException if messageUri is empty 2560 * {@hide} 2561 */ sendStoredMultipartTextMessage(Uri messageUri, String scAddress, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)2562 public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress, 2563 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 2564 if (messageUri == null) { 2565 throw new IllegalArgumentException("Empty message URI"); 2566 } 2567 final Context context = ActivityThread.currentApplication().getApplicationContext(); 2568 resolveSubscriptionForOperation(new SubscriptionResolverResult() { 2569 @Override 2570 public void onSuccess(int subId) { 2571 try { 2572 ISms iSms = getISmsServiceOrThrow(); 2573 iSms.sendStoredMultipartText(subId, ActivityThread.currentPackageName(), 2574 messageUri, scAddress, sentIntents, deliveryIntents); 2575 } catch (RemoteException e) { 2576 Log.e(TAG, "sendStoredTextMessage: Couldn't send SMS - Exception: " 2577 + e.getMessage()); 2578 notifySmsGenericError(sentIntents); 2579 } 2580 } 2581 @Override 2582 public void onFailure() { 2583 notifySmsErrorNoDefaultSet(context, sentIntents); 2584 } 2585 }); 2586 } 2587 2588 /** 2589 * Send a system stored MMS message 2590 * 2591 * This is used for sending a previously sent, but failed-to-send, message or 2592 * for sending a text message that has been stored as a draft. 2593 * 2594 * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation 2595 * dialog. If this method is called on a device that has multiple active subscriptions, this 2596 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 2597 * default subscription is defined, the subscription ID associated with this message will be 2598 * INVALID, which will result in the operation being completed on the subscription associated 2599 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 2600 * operation is performed on the correct subscription. 2601 * </p> 2602 * 2603 * @param messageUri the URI of the stored message 2604 * @param configOverrides the carrier-specific messaging configuration values to override for 2605 * sending the message. 2606 * @param sentIntent if not NULL this <code>PendingIntent</code> is 2607 * broadcast when the message is successfully sent, or failed 2608 * @throws IllegalArgumentException if messageUri is empty 2609 * {@hide} 2610 */ sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides, PendingIntent sentIntent)2611 public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides, 2612 PendingIntent sentIntent) { 2613 if (messageUri == null) { 2614 throw new IllegalArgumentException("Empty message URI"); 2615 } 2616 try { 2617 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2618 if (iMms != null) { 2619 iMms.sendStoredMessage( 2620 getSubscriptionId(), ActivityThread.currentPackageName(), messageUri, 2621 configOverrides, sentIntent); 2622 } 2623 } catch (RemoteException ex) { 2624 // ignore it 2625 } 2626 } 2627 2628 /** 2629 * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system 2630 * 2631 * When this flag is on, all SMS/MMS sent/received are stored by system automatically 2632 * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system 2633 * automatically 2634 * 2635 * This flag can only be changed by default SMS apps 2636 * 2637 * @param enabled Whether to enable message auto persisting 2638 * {@hide} 2639 */ setAutoPersisting(boolean enabled)2640 public void setAutoPersisting(boolean enabled) { 2641 try { 2642 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2643 if (iMms != null) { 2644 iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled); 2645 } 2646 } catch (RemoteException ex) { 2647 // ignore it 2648 } 2649 } 2650 2651 /** 2652 * Get the value of the flag to automatically write sent/received SMS/MMS messages into system 2653 * 2654 * When this flag is on, all SMS/MMS sent/received are stored by system automatically 2655 * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system 2656 * automatically 2657 * 2658 * @return the current value of the auto persist flag 2659 * {@hide} 2660 */ getAutoPersisting()2661 public boolean getAutoPersisting() { 2662 try { 2663 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2664 if (iMms != null) { 2665 return iMms.getAutoPersisting(); 2666 } 2667 } catch (RemoteException ex) { 2668 // ignore it 2669 } 2670 return false; 2671 } 2672 2673 /** 2674 * Get carrier-dependent configuration values. 2675 * 2676 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 2677 * applications or the Telephony framework and will never trigger an SMS disambiguation 2678 * dialog. If this method is called on a device that has multiple active subscriptions, this 2679 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 2680 * default subscription is defined, the subscription ID associated with this message will be 2681 * INVALID, which will result in the operation being completed on the subscription associated 2682 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 2683 * operation is performed on the correct subscription. 2684 * </p> 2685 * 2686 * @return bundle key/values pairs of configuration values 2687 */ getCarrierConfigValues()2688 public Bundle getCarrierConfigValues() { 2689 try { 2690 IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); 2691 if (iMms != null) { 2692 return iMms.getCarrierConfigValues(getSubscriptionId()); 2693 } 2694 } catch (RemoteException ex) { 2695 // ignore it 2696 } 2697 return null; 2698 } 2699 2700 /** 2701 * Create a single use app specific incoming SMS request for the calling package. 2702 * 2703 * This method returns a token that if included in a subsequent incoming SMS message will cause 2704 * {@code intent} to be sent with the SMS data. 2705 * 2706 * The token is only good for one use, after an SMS has been received containing the token all 2707 * subsequent SMS messages with the token will be routed as normal. 2708 * 2709 * An app can only have one request at a time, if the app already has a request pending it will 2710 * be replaced with a new request. 2711 * 2712 * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation 2713 * dialog. If this method is called on a device that has multiple active subscriptions, this 2714 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 2715 * default subscription is defined, the subscription ID associated with this message will be 2716 * INVALID, which will result in the operation being completed on the subscription associated 2717 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 2718 * operation is performed on the correct subscription. 2719 * </p> 2720 * 2721 * @return Token to include in an SMS message. The token will be 11 characters long. 2722 * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent 2723 */ createAppSpecificSmsToken(PendingIntent intent)2724 public String createAppSpecificSmsToken(PendingIntent intent) { 2725 try { 2726 ISms iccSms = getISmsServiceOrThrow(); 2727 return iccSms.createAppSpecificSmsToken(getSubscriptionId(), 2728 ActivityThread.currentPackageName(), intent); 2729 2730 } catch (RemoteException ex) { 2731 ex.rethrowFromSystemServer(); 2732 return null; 2733 } 2734 } 2735 2736 /** callback for providing asynchronous sms messages for financial app. */ 2737 public abstract static class FinancialSmsCallback { 2738 /** 2739 * Callback to send sms messages back to financial app asynchronously. 2740 * 2741 * @param msgs SMS messages. 2742 */ onFinancialSmsMessages(CursorWindow msgs)2743 public abstract void onFinancialSmsMessages(CursorWindow msgs); 2744 }; 2745 2746 /** 2747 * Get SMS messages for the calling financial app. 2748 * The result will be delivered asynchronously in the passing in callback interface. 2749 * 2750 * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation 2751 * dialog. If this method is called on a device that has multiple active subscriptions, this 2752 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 2753 * default subscription is defined, the subscription ID associated with this message will be 2754 * INVALID, which will result in the operation being completed on the subscription associated 2755 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 2756 * operation is performed on the correct subscription. 2757 * </p> 2758 * 2759 * @param params the parameters to filter SMS messages returned. 2760 * @param executor the executor on which callback will be invoked. 2761 * @param callback a callback to receive CursorWindow with SMS messages. 2762 */ 2763 @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) getSmsMessagesForFinancialApp( Bundle params, @NonNull @CallbackExecutor Executor executor, @NonNull FinancialSmsCallback callback)2764 public void getSmsMessagesForFinancialApp( 2765 Bundle params, 2766 @NonNull @CallbackExecutor Executor executor, 2767 @NonNull FinancialSmsCallback callback) { 2768 try { 2769 ISms iccSms = getISmsServiceOrThrow(); 2770 iccSms.getSmsMessagesForFinancialApp( 2771 getSubscriptionId(), ActivityThread.currentPackageName(), params, 2772 new IFinancialSmsCallback.Stub() { 2773 public void onGetSmsMessagesForFinancialApp(CursorWindow msgs) { 2774 Binder.withCleanCallingIdentity(() -> executor.execute( 2775 () -> callback.onFinancialSmsMessages(msgs))); 2776 }}); 2777 } catch (RemoteException ex) { 2778 ex.rethrowFromSystemServer(); 2779 } 2780 } 2781 2782 /** 2783 * @see #createAppSpecificSmsTokenWithPackageInfo(). 2784 * The prefixes is a list of prefix {@code String} separated by this delimiter. 2785 * @hide 2786 */ 2787 public static final String REGEX_PREFIX_DELIMITER = ","; 2788 /** 2789 * @see #createAppSpecificSmsTokenWithPackageInfo(). 2790 * The success status to be added into the intent to be sent to the calling package. 2791 * @hide 2792 */ 2793 public static final int RESULT_STATUS_SUCCESS = 0; 2794 /** 2795 * @see #createAppSpecificSmsTokenWithPackageInfo(). 2796 * The timeout status to be added into the intent to be sent to the calling package. 2797 * @hide 2798 */ 2799 public static final int RESULT_STATUS_TIMEOUT = 1; 2800 /** 2801 * @see #createAppSpecificSmsTokenWithPackageInfo(). 2802 * Intent extra key of the retrieved SMS message as a {@code String}. 2803 * @hide 2804 */ 2805 public static final String EXTRA_SMS_MESSAGE = "android.telephony.extra.SMS_MESSAGE"; 2806 /** 2807 * @see #createAppSpecificSmsTokenWithPackageInfo(). 2808 * Intent extra key of SMS retriever status, which indicates whether the request for the 2809 * coming SMS message is SUCCESS or TIMEOUT 2810 * @hide 2811 */ 2812 public static final String EXTRA_STATUS = "android.telephony.extra.STATUS"; 2813 /** 2814 * @see #createAppSpecificSmsTokenWithPackageInfo(). 2815 * [Optional] Intent extra key of the retrieved Sim card subscription Id if any. {@code int} 2816 * @hide 2817 */ 2818 public static final String EXTRA_SIM_SUBSCRIPTION_ID = 2819 "android.telephony.extra.SIM_SUBSCRIPTION_ID"; 2820 2821 /** 2822 * Create a single use app specific incoming SMS request for the calling package. 2823 * 2824 * This method returns a token that if included in a subsequent incoming SMS message, and the 2825 * SMS message has a prefix from the given prefixes list, the provided {@code intent} will be 2826 * sent with the SMS data to the calling package. 2827 * 2828 * The token is only good for one use within a reasonable amount of time. After an SMS has been 2829 * received containing the token all subsequent SMS messages with the token will be routed as 2830 * normal. 2831 * 2832 * An app can only have one request at a time, if the app already has a request pending it will 2833 * be replaced with a new request. 2834 * 2835 * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation 2836 * dialog. If this method is called on a device that has multiple active subscriptions, this 2837 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 2838 * default subscription is defined, the subscription ID associated with this message will be 2839 * INVALID, which will result in the operation being completed on the subscription associated 2840 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 2841 * operation is performed on the correct subscription. 2842 * </p> 2843 * 2844 * @param prefixes this is a list of prefixes string separated by REGEX_PREFIX_DELIMITER. The 2845 * matching SMS message should have at least one of the prefixes in the beginning of the 2846 * message. 2847 * @param intent this intent is sent when the matching SMS message is received. 2848 * @return Token to include in an SMS message. 2849 */ 2850 @Nullable createAppSpecificSmsTokenWithPackageInfo( @ullable String prefixes, @NonNull PendingIntent intent)2851 public String createAppSpecificSmsTokenWithPackageInfo( 2852 @Nullable String prefixes, @NonNull PendingIntent intent) { 2853 try { 2854 ISms iccSms = getISmsServiceOrThrow(); 2855 return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(), 2856 ActivityThread.currentPackageName(), prefixes, intent); 2857 2858 } catch (RemoteException ex) { 2859 ex.rethrowFromSystemServer(); 2860 return null; 2861 } 2862 } 2863 2864 /** 2865 * Filters a bundle to only contain MMS config variables. 2866 * 2867 * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS 2868 * config and unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the 2869 * supplied bundle. 2870 * 2871 * @param config a Bundle that contains MMS config variables and possibly more. 2872 * @return a new Bundle that only contains the MMS_CONFIG_* keys defined above. 2873 * @hide 2874 */ getMmsConfig(BaseBundle config)2875 public static Bundle getMmsConfig(BaseBundle config) { 2876 Bundle filtered = new Bundle(); 2877 filtered.putBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID, 2878 config.getBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID)); 2879 filtered.putBoolean(MMS_CONFIG_MMS_ENABLED, config.getBoolean(MMS_CONFIG_MMS_ENABLED)); 2880 filtered.putBoolean(MMS_CONFIG_GROUP_MMS_ENABLED, 2881 config.getBoolean(MMS_CONFIG_GROUP_MMS_ENABLED)); 2882 filtered.putBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED, 2883 config.getBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED)); 2884 filtered.putBoolean(MMS_CONFIG_ALIAS_ENABLED, config.getBoolean(MMS_CONFIG_ALIAS_ENABLED)); 2885 filtered.putBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO, 2886 config.getBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO)); 2887 filtered.putBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED, 2888 config.getBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED)); 2889 filtered.putBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED, 2890 config.getBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED)); 2891 filtered.putBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, 2892 config.getBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION)); 2893 filtered.putBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES, 2894 config.getBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES)); 2895 filtered.putBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED, 2896 config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED)); 2897 filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED, 2898 config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED)); 2899 filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION, 2900 config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION)); 2901 filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE)); 2902 filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH)); 2903 filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT)); 2904 filtered.putInt(MMS_CONFIG_RECIPIENT_LIMIT, config.getInt(MMS_CONFIG_RECIPIENT_LIMIT)); 2905 filtered.putInt(MMS_CONFIG_ALIAS_MIN_CHARS, config.getInt(MMS_CONFIG_ALIAS_MIN_CHARS)); 2906 filtered.putInt(MMS_CONFIG_ALIAS_MAX_CHARS, config.getInt(MMS_CONFIG_ALIAS_MAX_CHARS)); 2907 filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD, 2908 config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD)); 2909 filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD, 2910 config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD)); 2911 filtered.putInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE, 2912 config.getInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE)); 2913 filtered.putInt(MMS_CONFIG_SUBJECT_MAX_LENGTH, 2914 config.getInt(MMS_CONFIG_SUBJECT_MAX_LENGTH)); 2915 filtered.putInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT, 2916 config.getInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT)); 2917 filtered.putString(MMS_CONFIG_UA_PROF_TAG_NAME, 2918 config.getString(MMS_CONFIG_UA_PROF_TAG_NAME)); 2919 filtered.putString(MMS_CONFIG_USER_AGENT, config.getString(MMS_CONFIG_USER_AGENT)); 2920 filtered.putString(MMS_CONFIG_UA_PROF_URL, config.getString(MMS_CONFIG_UA_PROF_URL)); 2921 filtered.putString(MMS_CONFIG_HTTP_PARAMS, config.getString(MMS_CONFIG_HTTP_PARAMS)); 2922 filtered.putString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER, 2923 config.getString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER)); 2924 filtered.putString(MMS_CONFIG_NAI_SUFFIX, config.getString(MMS_CONFIG_NAI_SUFFIX)); 2925 filtered.putBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS, 2926 config.getBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS)); 2927 filtered.putBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER, 2928 config.getBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER)); 2929 return filtered; 2930 } 2931 2932 /** @hide */ 2933 @Retention(RetentionPolicy.SOURCE) 2934 @IntDef(prefix = {"SMS_CATEGORY_"}, 2935 value = { 2936 SmsManager.SMS_CATEGORY_NOT_SHORT_CODE, 2937 SmsManager.SMS_CATEGORY_FREE_SHORT_CODE, 2938 SmsManager.SMS_CATEGORY_STANDARD_SHORT_CODE, 2939 SmsManager.SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE, 2940 SmsManager.SMS_CATEGORY_PREMIUM_SHORT_CODE}) 2941 public @interface SmsShortCodeCategory {} 2942 2943 /** 2944 * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for regular 2945 * phone numbers. 2946 * @hide 2947 */ 2948 @TestApi 2949 public static final int SMS_CATEGORY_NOT_SHORT_CODE = 0; 2950 /** 2951 * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for free 2952 * (no cost) short codes. 2953 * @hide 2954 */ 2955 @TestApi 2956 public static final int SMS_CATEGORY_FREE_SHORT_CODE = 1; 2957 /** 2958 * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for 2959 * standard rate (non-premium) 2960 * short codes. 2961 * @hide 2962 */ 2963 @TestApi 2964 public static final int SMS_CATEGORY_STANDARD_SHORT_CODE = 2; 2965 /** 2966 * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for possible 2967 * premium short codes. 2968 * @hide 2969 */ 2970 @TestApi 2971 public static final int SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3; 2972 /** 2973 * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for 2974 * premium short codes. 2975 * @hide 2976 */ 2977 @TestApi 2978 public static final int SMS_CATEGORY_PREMIUM_SHORT_CODE = 4; 2979 2980 /** 2981 * Check if the destination address is a possible premium short code. 2982 * NOTE: the caller is expected to strip non-digits from the destination number with 2983 * {@link PhoneNumberUtils#extractNetworkPortion} before calling this method. 2984 * 2985 * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier 2986 * applications or the Telephony framework and will never trigger an SMS disambiguation 2987 * dialog. If this method is called on a device that has multiple active subscriptions, this 2988 * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined 2989 * default subscription is defined, the subscription ID associated with this message will be 2990 * INVALID, which will result in the operation being completed on the subscription associated 2991 * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the 2992 * operation is performed on the correct subscription. 2993 * </p> 2994 * 2995 * @param destAddress the destination address to test for possible short code 2996 * @param countryIso the ISO country code 2997 * 2998 * @return 2999 * {@link SmsManager#SMS_CATEGORY_NOT_SHORT_CODE}, 3000 * {@link SmsManager#SMS_CATEGORY_FREE_SHORT_CODE}, 3001 * {@link SmsManager#SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE}, 3002 * {@link SmsManager#SMS_CATEGORY_PREMIUM_SHORT_CODE}, or 3003 * {@link SmsManager#SMS_CATEGORY_STANDARD_SHORT_CODE} 3004 * 3005 * @hide 3006 */ 3007 @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) 3008 @TestApi checkSmsShortCodeDestination( String destAddress, String countryIso)3009 public @SmsShortCodeCategory int checkSmsShortCodeDestination( 3010 String destAddress, String countryIso) { 3011 try { 3012 ISms iccISms = getISmsServiceOrThrow(); 3013 if (iccISms != null) { 3014 return iccISms.checkSmsShortCodeDestination(getSubscriptionId(), 3015 ActivityThread.currentPackageName(), destAddress, countryIso); 3016 } 3017 } catch (RemoteException e) { 3018 Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e); 3019 } 3020 return SmsManager.SMS_CATEGORY_NOT_SHORT_CODE; 3021 } 3022 } 3023