1 /* 2 * Copyright (C) 2006 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 com.android.internal.telephony; 18 19 import static android.Manifest.permission.SEND_SMS_NO_CONFIRMATION; 20 import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PERIOD_NOT_SPECIFIED; 21 import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; 22 import static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE; 23 import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE; 24 import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED; 25 import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE; 26 import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU; 27 import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF; 28 import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED; 29 import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED; 30 31 import android.annotation.Nullable; 32 import android.annotation.UserIdInt; 33 import android.app.Activity; 34 import android.app.AlertDialog; 35 import android.app.PendingIntent; 36 import android.app.PendingIntent.CanceledException; 37 import android.content.ContentResolver; 38 import android.content.ContentValues; 39 import android.content.Context; 40 import android.content.DialogInterface; 41 import android.content.Intent; 42 import android.content.pm.ApplicationInfo; 43 import android.content.pm.PackageInfo; 44 import android.content.pm.PackageManager; 45 import android.content.res.Resources; 46 import android.database.ContentObserver; 47 import android.database.sqlite.SqliteWrapper; 48 import android.net.Uri; 49 import android.os.AsyncResult; 50 import android.os.Binder; 51 import android.os.Handler; 52 import android.os.Message; 53 import android.os.Process; 54 import android.os.RemoteException; 55 import android.os.UserHandle; 56 import android.provider.Settings; 57 import android.provider.Telephony; 58 import android.provider.Telephony.Sms; 59 import android.service.carrier.CarrierMessagingService; 60 import android.service.carrier.ICarrierMessagingCallback; 61 import android.service.carrier.ICarrierMessagingService; 62 import android.telephony.CarrierMessagingServiceManager; 63 import android.telephony.PhoneNumberUtils; 64 import android.telephony.Rlog; 65 import android.telephony.ServiceState; 66 import android.telephony.SmsManager; 67 import android.telephony.TelephonyManager; 68 import android.text.Html; 69 import android.text.Spanned; 70 import android.text.TextUtils; 71 import android.util.EventLog; 72 import android.view.LayoutInflater; 73 import android.view.View; 74 import android.view.ViewGroup; 75 import android.view.WindowManager; 76 import android.widget.Button; 77 import android.widget.CheckBox; 78 import android.widget.CompoundButton; 79 import android.widget.TextView; 80 81 import com.android.internal.R; 82 import com.android.internal.annotations.VisibleForTesting; 83 import com.android.internal.telephony.cdma.sms.UserData; 84 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; 85 import com.android.internal.telephony.uicc.UiccCard; 86 import com.android.internal.telephony.uicc.UiccController; 87 88 import java.util.ArrayList; 89 import java.util.HashMap; 90 import java.util.List; 91 import java.util.Random; 92 import java.util.concurrent.atomic.AtomicBoolean; 93 import java.util.concurrent.atomic.AtomicInteger; 94 95 public abstract class SMSDispatcher extends Handler { 96 static final String TAG = "SMSDispatcher"; // accessed from inner class 97 static final boolean DBG = false; 98 private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg"; 99 protected static final String MAP_KEY_PDU = "pdu"; 100 protected static final String MAP_KEY_SMSC = "smsc"; 101 protected static final String MAP_KEY_DEST_ADDR = "destAddr"; 102 protected static final String MAP_KEY_SC_ADDR = "scAddr"; 103 protected static final String MAP_KEY_DEST_PORT = "destPort"; 104 protected static final String MAP_KEY_DATA = "data"; 105 protected static final String MAP_KEY_TEXT = "text"; 106 107 private static final int PREMIUM_RULE_USE_SIM = 1; 108 private static final int PREMIUM_RULE_USE_NETWORK = 2; 109 private static final int PREMIUM_RULE_USE_BOTH = 3; 110 private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM); 111 private final SettingsObserver mSettingsObserver; 112 113 /** SMS send complete. */ 114 protected static final int EVENT_SEND_SMS_COMPLETE = 2; 115 116 /** Retry sending a previously failed SMS message */ 117 private static final int EVENT_SEND_RETRY = 3; 118 119 /** Confirmation required for sending a large number of messages. */ 120 private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4; 121 122 /** Send the user confirmed SMS */ 123 static final int EVENT_SEND_CONFIRMED_SMS = 5; // accessed from inner class 124 125 /** Don't send SMS (user did not confirm). */ 126 static final int EVENT_STOP_SENDING = 7; // accessed from inner class 127 128 /** Confirmation required for third-party apps sending to an SMS short code. */ 129 private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8; 130 131 /** Confirmation required for third-party apps sending to an SMS short code. */ 132 private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9; 133 134 /** Handle status report from {@code CdmaInboundSmsHandler}. */ 135 protected static final int EVENT_HANDLE_STATUS_REPORT = 10; 136 137 // other 138 protected static final int EVENT_NEW_ICC_SMS = 14; 139 protected static final int EVENT_ICC_CHANGED = 15; 140 protected static final int EVENT_GET_IMS_SERVICE = 16; 141 142 143 protected Phone mPhone; 144 protected final Context mContext; 145 protected final ContentResolver mResolver; 146 protected final CommandsInterface mCi; 147 protected final TelephonyManager mTelephonyManager; 148 149 /** Maximum number of times to retry sending a failed SMS. */ 150 private static final int MAX_SEND_RETRIES = 3; 151 /** Delay before next send attempt on a failed SMS, in milliseconds. */ 152 private static final int SEND_RETRY_DELAY = 2000; 153 /** single part SMS */ 154 private static final int SINGLE_PART_SMS = 1; 155 /** Message sending queue limit */ 156 private static final int MO_MSG_QUEUE_LIMIT = 5; 157 158 /** 159 * Message reference for a CONCATENATED_8_BIT_REFERENCE or 160 * CONCATENATED_16_BIT_REFERENCE message set. Should be 161 * incremented for each set of concatenated messages. 162 * Static field shared by all dispatcher objects. 163 */ 164 private static int sConcatenatedRef = new Random().nextInt(256); 165 166 protected SmsDispatchersController mSmsDispatchersController; 167 168 /** Number of outgoing SmsTrackers waiting for user confirmation. */ 169 private int mPendingTrackerCount; 170 171 /* Flags indicating whether the current device allows sms service */ 172 protected boolean mSmsCapable = true; 173 protected boolean mSmsSendDisabled; 174 175 protected static int getNextConcatenatedRef() { 176 sConcatenatedRef += 1; 177 return sConcatenatedRef; 178 } 179 180 /** 181 * Create a new SMS dispatcher. 182 * @param phone the Phone to use 183 */ 184 protected SMSDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) { 185 mPhone = phone; 186 mSmsDispatchersController = smsDispatchersController; 187 mContext = phone.getContext(); 188 mResolver = mContext.getContentResolver(); 189 mCi = phone.mCi; 190 mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 191 mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext); 192 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 193 Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver); 194 195 mSmsCapable = mContext.getResources().getBoolean( 196 com.android.internal.R.bool.config_sms_capable); 197 mSmsSendDisabled = !mTelephonyManager.getSmsSendCapableForPhone( 198 mPhone.getPhoneId(), mSmsCapable); 199 Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat() 200 + " mSmsSendDisabled=" + mSmsSendDisabled); 201 } 202 203 /** 204 * Observe the secure setting for updated premium sms determination rules 205 */ 206 private static class SettingsObserver extends ContentObserver { 207 private final AtomicInteger mPremiumSmsRule; 208 private final Context mContext; 209 SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) { 210 super(handler); 211 mPremiumSmsRule = premiumSmsRule; 212 mContext = context; 213 onChange(false); // load initial value; 214 } 215 216 @Override 217 public void onChange(boolean selfChange) { 218 mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(), 219 Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM)); 220 } 221 } 222 223 protected void updatePhoneObject(Phone phone) { 224 mPhone = phone; 225 Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() ); 226 } 227 228 /** Unregister for incoming SMS events. */ 229 public void dispose() { 230 mContext.getContentResolver().unregisterContentObserver(mSettingsObserver); 231 } 232 233 /** 234 * The format of the message PDU in the associated broadcast intent. 235 * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format 236 * or "3gpp2" for CDMA/LTE messages in 3GPP2 format. 237 * 238 * Note: All applications which handle incoming SMS messages by processing the 239 * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent 240 * into the new methods in {@link android.telephony.SmsMessage} which take an 241 * extra format parameter. This is required in order to correctly decode the PDU on 242 * devices which require support for both 3GPP and 3GPP2 formats at the same time, 243 * such as CDMA/LTE devices and GSM/CDMA world phones. 244 * 245 * @return the format of the message PDU 246 */ 247 protected abstract String getFormat(); 248 249 /** 250 * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports 251 * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}. 252 * @param o the SmsMessage containing the status report 253 */ 254 protected void handleStatusReport(Object o) { 255 Rlog.d(TAG, "handleStatusReport() called with no subclass."); 256 } 257 258 /* TODO: Need to figure out how to keep track of status report routing in a 259 * persistent manner. If the phone process restarts (reboot or crash), 260 * we will lose this list and any status reports that come in after 261 * will be dropped. 262 */ 263 /** Sent messages awaiting a delivery status report. */ 264 protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>(); 265 266 /** 267 * Handles events coming from the phone stack. Overridden from handler. 268 * 269 * @param msg the message to handle 270 */ 271 @Override 272 public void handleMessage(Message msg) { 273 switch (msg.what) { 274 case EVENT_SEND_SMS_COMPLETE: 275 // An outbound SMS has been successfully transferred, or failed. 276 handleSendComplete((AsyncResult) msg.obj); 277 break; 278 279 case EVENT_SEND_RETRY: 280 Rlog.d(TAG, "SMS retry.."); 281 sendRetrySms((SmsTracker) msg.obj); 282 break; 283 284 case EVENT_SEND_LIMIT_REACHED_CONFIRMATION: 285 handleReachSentLimit((SmsTracker)(msg.obj)); 286 break; 287 288 case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE: 289 handleConfirmShortCode(false, (SmsTracker)(msg.obj)); 290 break; 291 292 case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE: 293 handleConfirmShortCode(true, (SmsTracker)(msg.obj)); 294 break; 295 296 case EVENT_SEND_CONFIRMED_SMS: 297 { 298 SmsTracker tracker = (SmsTracker) msg.obj; 299 if (tracker.isMultipart()) { 300 sendMultipartSms(tracker); 301 } else { 302 if (mPendingTrackerCount > 1) { 303 tracker.mExpectMore = true; 304 } else { 305 tracker.mExpectMore = false; 306 } 307 sendSms(tracker); 308 } 309 mPendingTrackerCount--; 310 break; 311 } 312 313 case EVENT_STOP_SENDING: 314 { 315 SmsTracker tracker = (SmsTracker) msg.obj; 316 if (msg.arg1 == ConfirmDialogListener.SHORT_CODE_MSG) { 317 if (msg.arg2 == ConfirmDialogListener.NEVER_ALLOW) { 318 tracker.onFailed(mContext, 319 RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, 0/*errorCode*/); 320 Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - " 321 + "sending SHORT_CODE_NEVER_ALLOWED error code."); 322 } else { 323 tracker.onFailed(mContext, 324 RESULT_ERROR_SHORT_CODE_NOT_ALLOWED, 0/*errorCode*/); 325 Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - " 326 + "sending SHORT_CODE_NOT_ALLOWED error code."); 327 } 328 } else if (msg.arg1 == ConfirmDialogListener.RATE_LIMIT) { 329 tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/); 330 Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - " 331 + "sending LIMIT_EXCEEDED error code."); 332 } else { 333 Rlog.e(TAG, "SMSDispatcher: EVENT_STOP_SENDING - unexpected cases."); 334 } 335 mPendingTrackerCount--; 336 break; 337 } 338 339 case EVENT_HANDLE_STATUS_REPORT: 340 handleStatusReport(msg.obj); 341 break; 342 343 default: 344 Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what); 345 } 346 } 347 348 /** 349 * Use the carrier messaging service to send a data or text SMS. 350 */ 351 protected abstract class SmsSender extends CarrierMessagingServiceManager { 352 protected final SmsTracker mTracker; 353 // Initialized in sendSmsByCarrierApp 354 protected volatile SmsSenderCallback mSenderCallback; 355 356 protected SmsSender(SmsTracker tracker) { 357 mTracker = tracker; 358 } 359 360 public void sendSmsByCarrierApp(String carrierPackageName, 361 SmsSenderCallback senderCallback) { 362 mSenderCallback = senderCallback; 363 if (!bindToCarrierMessagingService(mContext, carrierPackageName)) { 364 Rlog.e(TAG, "bindService() for carrier messaging service failed"); 365 mSenderCallback.onSendSmsComplete( 366 CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 367 0 /* messageRef */); 368 } else { 369 Rlog.d(TAG, "bindService() for carrier messaging service succeeded"); 370 } 371 } 372 } 373 374 private static int getSendSmsFlag(@Nullable PendingIntent deliveryIntent) { 375 if (deliveryIntent == null) { 376 return 0; 377 } 378 return CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS; 379 } 380 381 /** 382 * Use the carrier messaging service to send a text SMS. 383 */ 384 protected final class TextSmsSender extends SmsSender { 385 public TextSmsSender(SmsTracker tracker) { 386 super(tracker); 387 } 388 389 @Override 390 protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { 391 HashMap<String, Object> map = mTracker.getData(); 392 String text = (String) map.get(MAP_KEY_TEXT); 393 394 if (text != null) { 395 try { 396 carrierMessagingService.sendTextSms(text, getSubId(), 397 mTracker.mDestAddress, getSendSmsFlag(mTracker.mDeliveryIntent), 398 mSenderCallback); 399 } catch (RemoteException e) { 400 Rlog.e(TAG, "Exception sending the SMS: " + e); 401 mSenderCallback.onSendSmsComplete( 402 CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 403 0 /* messageRef */); 404 } 405 } else { 406 mSenderCallback.onSendSmsComplete( 407 CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 408 0 /* messageRef */); 409 } 410 } 411 } 412 413 /** 414 * Use the carrier messaging service to send a data SMS. 415 */ 416 protected final class DataSmsSender extends SmsSender { 417 public DataSmsSender(SmsTracker tracker) { 418 super(tracker); 419 } 420 421 @Override 422 protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { 423 HashMap<String, Object> map = mTracker.getData(); 424 byte[] data = (byte[]) map.get(MAP_KEY_DATA); 425 int destPort = (int) map.get(MAP_KEY_DEST_PORT); 426 427 if (data != null) { 428 try { 429 carrierMessagingService.sendDataSms(data, getSubId(), 430 mTracker.mDestAddress, destPort, 431 getSendSmsFlag(mTracker.mDeliveryIntent), mSenderCallback); 432 } catch (RemoteException e) { 433 Rlog.e(TAG, "Exception sending the SMS: " + e); 434 mSenderCallback.onSendSmsComplete( 435 CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 436 0 /* messageRef */); 437 } 438 } else { 439 mSenderCallback.onSendSmsComplete( 440 CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 441 0 /* messageRef */); 442 } 443 } 444 } 445 446 /** 447 * Callback for TextSmsSender and DataSmsSender from the carrier messaging service. 448 * Once the result is ready, the carrier messaging service connection is disposed. 449 */ 450 protected final class SmsSenderCallback extends ICarrierMessagingCallback.Stub { 451 private final SmsSender mSmsSender; 452 453 public SmsSenderCallback(SmsSender smsSender) { 454 mSmsSender = smsSender; 455 } 456 457 /** 458 * This method should be called only once. 459 */ 460 @Override 461 public void onSendSmsComplete(int result, int messageRef) { 462 checkCallerIsPhoneOrCarrierApp(); 463 final long identity = Binder.clearCallingIdentity(); 464 try { 465 mSmsSender.disposeConnection(mContext); 466 processSendSmsResponse(mSmsSender.mTracker, result, messageRef); 467 } finally { 468 Binder.restoreCallingIdentity(identity); 469 } 470 } 471 472 @Override 473 public void onSendMultipartSmsComplete(int result, int[] messageRefs) { 474 Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result); 475 } 476 477 @Override 478 public void onFilterComplete(int result) { 479 Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result); 480 } 481 482 @Override 483 public void onSendMmsComplete(int result, byte[] sendConfPdu) { 484 Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result); 485 } 486 487 @Override 488 public void onDownloadMmsComplete(int result) { 489 Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result); 490 } 491 } 492 493 private void processSendSmsResponse(SmsTracker tracker, int result, int messageRef) { 494 if (tracker == null) { 495 Rlog.e(TAG, "processSendSmsResponse: null tracker"); 496 return; 497 } 498 499 SmsResponse smsResponse = new SmsResponse( 500 messageRef, null /* ackPdu */, -1 /* unknown error code */); 501 502 switch (result) { 503 case CarrierMessagingService.SEND_STATUS_OK: 504 Rlog.d(TAG, "Sending SMS by IP succeeded."); 505 sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE, 506 new AsyncResult(tracker, 507 smsResponse, 508 null /* exception*/ ))); 509 break; 510 case CarrierMessagingService.SEND_STATUS_ERROR: 511 Rlog.d(TAG, "Sending SMS by IP failed."); 512 sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE, 513 new AsyncResult(tracker, smsResponse, 514 new CommandException(CommandException.Error.GENERIC_FAILURE)))); 515 break; 516 case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK: 517 Rlog.d(TAG, "Sending SMS by IP failed. Retry on carrier network."); 518 sendSubmitPdu(tracker); 519 break; 520 default: 521 Rlog.d(TAG, "Unknown result " + result + " Retry on carrier network."); 522 sendSubmitPdu(tracker); 523 } 524 } 525 526 /** 527 * Use the carrier messaging service to send a multipart text SMS. 528 */ 529 private final class MultipartSmsSender extends CarrierMessagingServiceManager { 530 private final List<String> mParts; 531 public final SmsTracker[] mTrackers; 532 // Initialized in sendSmsByCarrierApp 533 private volatile MultipartSmsSenderCallback mSenderCallback; 534 535 MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) { 536 mParts = parts; 537 mTrackers = trackers; 538 } 539 540 void sendSmsByCarrierApp(String carrierPackageName, 541 MultipartSmsSenderCallback senderCallback) { 542 mSenderCallback = senderCallback; 543 if (!bindToCarrierMessagingService(mContext, carrierPackageName)) { 544 Rlog.e(TAG, "bindService() for carrier messaging service failed"); 545 mSenderCallback.onSendMultipartSmsComplete( 546 CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 547 null /* smsResponse */); 548 } else { 549 Rlog.d(TAG, "bindService() for carrier messaging service succeeded"); 550 } 551 } 552 553 @Override 554 protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { 555 try { 556 carrierMessagingService.sendMultipartTextSms( 557 mParts, getSubId(), mTrackers[0].mDestAddress, 558 getSendSmsFlag(mTrackers[0].mDeliveryIntent), mSenderCallback); 559 } catch (RemoteException e) { 560 Rlog.e(TAG, "Exception sending the SMS: " + e); 561 mSenderCallback.onSendMultipartSmsComplete( 562 CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 563 null /* smsResponse */); 564 } 565 } 566 } 567 568 /** 569 * Callback for MultipartSmsSender from the carrier messaging service. 570 * Once the result is ready, the carrier messaging service connection is disposed. 571 */ 572 private final class MultipartSmsSenderCallback extends ICarrierMessagingCallback.Stub { 573 private final MultipartSmsSender mSmsSender; 574 575 MultipartSmsSenderCallback(MultipartSmsSender smsSender) { 576 mSmsSender = smsSender; 577 } 578 579 @Override 580 public void onSendSmsComplete(int result, int messageRef) { 581 Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result); 582 } 583 584 /** 585 * This method should be called only once. 586 */ 587 @Override 588 public void onSendMultipartSmsComplete(int result, int[] messageRefs) { 589 mSmsSender.disposeConnection(mContext); 590 591 if (mSmsSender.mTrackers == null) { 592 Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers."); 593 return; 594 } 595 596 checkCallerIsPhoneOrCarrierApp(); 597 final long identity = Binder.clearCallingIdentity(); 598 try { 599 for (int i = 0; i < mSmsSender.mTrackers.length; i++) { 600 int messageRef = 0; 601 if (messageRefs != null && messageRefs.length > i) { 602 messageRef = messageRefs[i]; 603 } 604 processSendSmsResponse(mSmsSender.mTrackers[i], result, messageRef); 605 } 606 } finally { 607 Binder.restoreCallingIdentity(identity); 608 } 609 } 610 611 @Override 612 public void onFilterComplete(int result) { 613 Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result); 614 } 615 616 @Override 617 public void onSendMmsComplete(int result, byte[] sendConfPdu) { 618 Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result); 619 } 620 621 @Override 622 public void onDownloadMmsComplete(int result) { 623 Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result); 624 } 625 } 626 627 /** 628 * Send an SMS PDU. Usually just calls {@link sendRawPdu}. 629 */ 630 private void sendSubmitPdu(SmsTracker tracker) { 631 if (shouldBlockSmsForEcbm()) { 632 Rlog.d(TAG, "Block SMS in Emergency Callback mode"); 633 tracker.onFailed(mContext, SmsManager.RESULT_ERROR_NO_SERVICE, 0/*errorCode*/); 634 } else { 635 sendRawPdu(tracker); 636 } 637 } 638 639 /** 640 * @return true if MO SMS should be blocked for Emergency Callback Mode. 641 */ 642 protected abstract boolean shouldBlockSmsForEcbm(); 643 644 /** 645 * Called when SMS send completes. Broadcasts a sentIntent on success. 646 * On failure, either sets up retries or broadcasts a sentIntent with 647 * the failure in the result code. 648 * 649 * @param ar AsyncResult passed into the message handler. ar.result should 650 * an SmsResponse instance if send was successful. ar.userObj 651 * should be an SmsTracker instance. 652 */ 653 protected void handleSendComplete(AsyncResult ar) { 654 SmsTracker tracker = (SmsTracker) ar.userObj; 655 PendingIntent sentIntent = tracker.mSentIntent; 656 657 if (ar.result != null) { 658 tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef; 659 } else { 660 Rlog.d(TAG, "SmsResponse was null"); 661 } 662 663 if (ar.exception == null) { 664 if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent); 665 666 if (tracker.mDeliveryIntent != null) { 667 // Expecting a status report. Add it to the list. 668 deliveryPendingList.add(tracker); 669 } 670 tracker.onSent(mContext); 671 } else { 672 if (DBG) Rlog.d(TAG, "SMS send failed"); 673 674 int ss = mPhone.getServiceState().getState(); 675 676 if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) { 677 // This is retry after failure over IMS but voice is not available. 678 // Set retry to max allowed, so no retry is sent and 679 // cause RESULT_ERROR_GENERIC_FAILURE to be returned to app. 680 tracker.mRetryCount = MAX_SEND_RETRIES; 681 682 Rlog.d(TAG, "handleSendComplete: Skipping retry: " 683 +" isIms()="+isIms() 684 +" mRetryCount="+tracker.mRetryCount 685 +" mImsRetry="+tracker.mImsRetry 686 +" mMessageRef="+tracker.mMessageRef 687 +" SS= "+mPhone.getServiceState().getState()); 688 } 689 690 // if sms over IMS is not supported on data and voice is not available... 691 if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { 692 tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/); 693 } else if ((((CommandException)(ar.exception)).getCommandError() 694 == CommandException.Error.SMS_FAIL_RETRY) && 695 tracker.mRetryCount < MAX_SEND_RETRIES) { 696 // Retry after a delay if needed. 697 // TODO: According to TS 23.040, 9.2.3.6, we should resend 698 // with the same TP-MR as the failed message, and 699 // TP-RD set to 1. However, we don't have a means of 700 // knowing the MR for the failed message (EF_SMSstatus 701 // may or may not have the MR corresponding to this 702 // message, depending on the failure). Also, in some 703 // implementations this retry is handled by the baseband. 704 tracker.mRetryCount++; 705 Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker); 706 sendMessageDelayed(retryMsg, SEND_RETRY_DELAY); 707 } else { 708 int errorCode = 0; 709 if (ar.result != null) { 710 errorCode = ((SmsResponse)ar.result).mErrorCode; 711 } 712 int error = RESULT_ERROR_GENERIC_FAILURE; 713 if (((CommandException)(ar.exception)).getCommandError() 714 == CommandException.Error.FDN_CHECK_FAILURE) { 715 error = RESULT_ERROR_FDN_CHECK_FAILURE; 716 } 717 tracker.onFailed(mContext, error, errorCode); 718 } 719 } 720 } 721 722 /** 723 * Handles outbound message when the phone is not in service. 724 * 725 * @param ss Current service state. Valid values are: 726 * OUT_OF_SERVICE 727 * EMERGENCY_ONLY 728 * POWER_OFF 729 * @param sentIntent the PendingIntent to send the error to 730 */ 731 protected static void handleNotInService(int ss, PendingIntent sentIntent) { 732 if (sentIntent != null) { 733 try { 734 if (ss == ServiceState.STATE_POWER_OFF) { 735 sentIntent.send(RESULT_ERROR_RADIO_OFF); 736 } else { 737 sentIntent.send(RESULT_ERROR_NO_SERVICE); 738 } 739 } catch (CanceledException ex) { 740 Rlog.e(TAG, "Failed to send result"); 741 } 742 } 743 } 744 745 /** 746 * @param ss service state 747 * @return The result error based on input service state for not in service error 748 */ 749 protected static int getNotInServiceError(int ss) { 750 if (ss == ServiceState.STATE_POWER_OFF) { 751 return RESULT_ERROR_RADIO_OFF; 752 } 753 return RESULT_ERROR_NO_SERVICE; 754 } 755 756 /** 757 * Send a data based SMS to a specific application port. 758 * 759 * @param destAddr the address to send the message to 760 * @param scAddr is the service center address or null to use 761 * the current default SMSC 762 * @param destPort the port to deliver the message to 763 * @param data the body of the message to send 764 * @param sentIntent if not NULL this <code>PendingIntent</code> is 765 * broadcast when the message is successfully sent, or failed. 766 * The result code will be <code>Activity.RESULT_OK<code> for success, 767 * or one of these errors:<br> 768 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 769 * <code>RESULT_ERROR_RADIO_OFF</code><br> 770 * <code>RESULT_ERROR_NULL_PDU</code><br> 771 * <code>RESULT_ERROR_NO_SERVICE</code><br>. 772 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 773 * the extra "errorCode" containing a radio technology specific value, 774 * generally only useful for troubleshooting.<br> 775 * The per-application based SMS control checks sentIntent. If sentIntent 776 * is NULL the caller will be checked against all unknown applications, 777 * which cause smaller number of SMS to be sent in checking period. 778 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 779 * broadcast when the message is delivered to the recipient. The 780 * raw pdu of the status report is in the extended data ("pdu"). 781 */ 782 protected void sendData(String destAddr, String scAddr, int destPort, 783 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 784 SmsMessageBase.SubmitPduBase pdu = getSubmitPdu( 785 scAddr, destAddr, destPort, data, (deliveryIntent != null)); 786 if (pdu != null) { 787 HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu); 788 SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), 789 null /*messageUri*/, false /*expectMore*/, 790 null /*fullMessageText*/, false /*isText*/, 791 true /*persistMessage*/); 792 793 if (!sendSmsByCarrierApp(true /* isDataSms */, tracker)) { 794 sendSubmitPdu(tracker); 795 } 796 } else { 797 Rlog.e(TAG, "SMSDispatcher.sendData(): getSubmitPdu() returned null"); 798 triggerSentIntentForFailure(sentIntent); 799 } 800 } 801 802 /** 803 * Send a text based SMS. 804 * @param destAddr the address to send the message to 805 * @param scAddr is the service center address or null to use 806 * the current default SMSC 807 * @param text the body of the message to send 808 * @param sentIntent if not NULL this <code>PendingIntent</code> is 809 * broadcast when the message is successfully sent, or failed. 810 * The result code will be <code>Activity.RESULT_OK<code> for success, 811 * or one of these errors:<br> 812 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 813 * <code>RESULT_ERROR_RADIO_OFF</code><br> 814 * <code>RESULT_ERROR_NULL_PDU</code><br> 815 * <code>RESULT_ERROR_NO_SERVICE</code><br>. 816 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 817 * the extra "errorCode" containing a radio technology specific value, 818 * generally only useful for troubleshooting.<br> 819 * The per-application based SMS control checks sentIntent. If sentIntent 820 * is NULL the caller will be checked against all unknown applications, 821 * which cause smaller number of SMS to be sent in checking period. 822 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 823 * broadcast when the message is delivered to the recipient. The 824 * @param messageUri optional URI of the message if it is already stored in the system 825 * @param callingPkg the calling package name 826 * @param persistMessage whether to save the sent message into SMS DB for a 827 * non-default SMS app. 828 * 829 * @param priority Priority level of the message 830 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 831 * --------------------------------- 832 * PRIORITY | Level of Priority 833 * --------------------------------- 834 * '00' | Normal 835 * '01' | Interactive 836 * '10' | Urgent 837 * '11' | Emergency 838 * ---------------------------------- 839 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 840 * @param expectMore is a boolean to indicate the sending messages through same link or not. 841 * @param validityPeriod Validity Period of the message in mins. 842 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 843 * Validity Period(Minimum) -> 5 mins 844 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 845 * Any Other values included Negative considered as Invalid Validity Period of the message. 846 */ 847 public void sendText(String destAddr, String scAddr, String text, 848 PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, 849 String callingPkg, boolean persistMessage, int priority, 850 boolean expectMore, int validityPeriod) { 851 Rlog.d(TAG, "sendText"); 852 SmsMessageBase.SubmitPduBase pdu = getSubmitPdu( 853 scAddr, destAddr, text, (deliveryIntent != null), null, priority, validityPeriod); 854 if (pdu != null) { 855 HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu); 856 SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), 857 messageUri, expectMore, text, true /*isText*/, 858 persistMessage, priority, validityPeriod); 859 860 if (!sendSmsByCarrierApp(false /* isDataSms */, tracker)) { 861 sendSubmitPdu(tracker); 862 } 863 } else { 864 Rlog.e(TAG, "SmsDispatcher.sendText(): getSubmitPdu() returned null"); 865 triggerSentIntentForFailure(sentIntent); 866 } 867 } 868 869 private void triggerSentIntentForFailure(PendingIntent sentIntent) { 870 if (sentIntent != null) { 871 try { 872 sentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); 873 } catch (CanceledException ex) { 874 Rlog.e(TAG, "Intent has been canceled!"); 875 } 876 } 877 } 878 879 private boolean sendSmsByCarrierApp(boolean isDataSms, SmsTracker tracker ) { 880 String carrierPackage = getCarrierAppPackageName(); 881 if (carrierPackage != null) { 882 Rlog.d(TAG, "Found carrier package."); 883 SmsSender smsSender; 884 if (isDataSms) { 885 smsSender = new DataSmsSender(tracker); 886 } else { 887 smsSender = new TextSmsSender(tracker); 888 } 889 smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender)); 890 return true; 891 } 892 893 return false; 894 } 895 896 protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, 897 String message, boolean statusReportRequested, SmsHeader smsHeader, 898 int priority, int validityPeriod); 899 900 protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, 901 int destPort, byte[] message, boolean statusReportRequested); 902 903 /** 904 * Calculate the number of septets needed to encode the message. This function should only be 905 * called for individual segments of multipart message. 906 * 907 * @param messageBody the message to encode 908 * @param use7bitOnly ignore (but still count) illegal characters if true 909 * @return TextEncodingDetails 910 */ 911 protected abstract TextEncodingDetails calculateLength(CharSequence messageBody, 912 boolean use7bitOnly); 913 914 /** 915 * Send a multi-part text based SMS. 916 * @param destAddr the address to send the message to 917 * @param scAddr is the service center address or null to use 918 * the current default SMSC 919 * @param parts an <code>ArrayList</code> of strings that, in order, 920 * comprise the original message 921 * @param sentIntents if not null, an <code>ArrayList</code> of 922 * <code>PendingIntent</code>s (one for each message part) that is 923 * broadcast when the corresponding message part has been sent. 924 * The result code will be <code>Activity.RESULT_OK<code> for success, 925 * or one of these errors: 926 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 927 * <code>RESULT_ERROR_RADIO_OFF</code> 928 * <code>RESULT_ERROR_NULL_PDU</code> 929 * <code>RESULT_ERROR_NO_SERVICE</code>. 930 * The per-application based SMS control checks sentIntent. If sentIntent 931 * is NULL the caller will be checked against all unknown applications, 932 * which cause smaller number of SMS to be sent in checking period. 933 * @param deliveryIntents if not null, an <code>ArrayList</code> of 934 * <code>PendingIntent</code>s (one for each message part) that is 935 * broadcast when the corresponding message part has been delivered 936 * to the recipient. The raw pdu of the status report is in the 937 * @param messageUri optional URI of the message if it is already stored in the system 938 * @param callingPkg the calling package name 939 * @param persistMessage whether to save the sent message into SMS DB for a 940 * non-default SMS app. 941 * @param priority Priority level of the message 942 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 943 * --------------------------------- 944 * PRIORITY | Level of Priority 945 * --------------------------------- 946 * '00' | Normal 947 * '01' | Interactive 948 * '10' | Urgent 949 * '11' | Emergency 950 * ---------------------------------- 951 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 952 * @param expectMore is a boolean to indicate the sending messages through same link or not. 953 * @param validityPeriod Validity Period of the message in mins. 954 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 955 * Validity Period(Minimum) -> 5 mins 956 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 957 * Any Other values included Negative considered as Invalid Validity Period of the message. 958 */ 959 protected void sendMultipartText(String destAddr, String scAddr, 960 ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, 961 ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, 962 boolean persistMessage, int priority, boolean expectMore, int validityPeriod) { 963 final String fullMessageText = getMultipartMessageText(parts); 964 int refNumber = getNextConcatenatedRef() & 0x00FF; 965 int msgCount = parts.size(); 966 int encoding = SmsConstants.ENCODING_UNKNOWN; 967 968 TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount]; 969 for (int i = 0; i < msgCount; i++) { 970 TextEncodingDetails details = calculateLength(parts.get(i), false); 971 if (encoding != details.codeUnitSize 972 && (encoding == SmsConstants.ENCODING_UNKNOWN 973 || encoding == SmsConstants.ENCODING_7BIT)) { 974 encoding = details.codeUnitSize; 975 } 976 encodingForParts[i] = details; 977 } 978 979 SmsTracker[] trackers = new SmsTracker[msgCount]; 980 981 // States to track at the message level (for all parts) 982 final AtomicInteger unsentPartCount = new AtomicInteger(msgCount); 983 final AtomicBoolean anyPartFailed = new AtomicBoolean(false); 984 985 for (int i = 0; i < msgCount; i++) { 986 SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); 987 concatRef.refNumber = refNumber; 988 concatRef.seqNumber = i + 1; // 1-based sequence 989 concatRef.msgCount = msgCount; 990 // TODO: We currently set this to true since our messaging app will never 991 // send more than 255 parts (it converts the message to MMS well before that). 992 // However, we should support 3rd party messaging apps that might need 16-bit 993 // references 994 // Note: It's not sufficient to just flip this bit to true; it will have 995 // ripple effects (several calculations assume 8-bit ref). 996 concatRef.isEightBits = true; 997 SmsHeader smsHeader = new SmsHeader(); 998 smsHeader.concatRef = concatRef; 999 1000 // Set the national language tables for 3GPP 7-bit encoding, if enabled. 1001 if (encoding == SmsConstants.ENCODING_7BIT) { 1002 smsHeader.languageTable = encodingForParts[i].languageTable; 1003 smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable; 1004 } 1005 1006 PendingIntent sentIntent = null; 1007 if (sentIntents != null && sentIntents.size() > i) { 1008 sentIntent = sentIntents.get(i); 1009 } 1010 1011 PendingIntent deliveryIntent = null; 1012 if (deliveryIntents != null && deliveryIntents.size() > i) { 1013 deliveryIntent = deliveryIntents.get(i); 1014 } 1015 1016 trackers[i] = 1017 getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding, 1018 sentIntent, deliveryIntent, (i == (msgCount - 1)), 1019 unsentPartCount, anyPartFailed, messageUri, 1020 fullMessageText, priority, expectMore, validityPeriod); 1021 trackers[i].mPersistMessage = persistMessage; 1022 } 1023 1024 if (parts == null || trackers == null || trackers.length == 0 1025 || trackers[0] == null) { 1026 Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers); 1027 return; 1028 } 1029 1030 String carrierPackage = getCarrierAppPackageName(); 1031 if (carrierPackage != null) { 1032 Rlog.d(TAG, "Found carrier package."); 1033 MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers); 1034 smsSender.sendSmsByCarrierApp(carrierPackage, 1035 new MultipartSmsSenderCallback(smsSender)); 1036 } else { 1037 Rlog.v(TAG, "No carrier package."); 1038 for (SmsTracker tracker : trackers) { 1039 if (tracker != null) { 1040 sendSubmitPdu(tracker); 1041 } else { 1042 Rlog.e(TAG, "Null tracker."); 1043 } 1044 } 1045 } 1046 } 1047 1048 /** 1049 * Create a new SubmitPdu and return the SMS tracker. 1050 */ 1051 private SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress, 1052 String message, SmsHeader smsHeader, int encoding, 1053 PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart, 1054 AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, 1055 String fullMessageText, int priority, boolean expectMore, int validityPeriod) { 1056 if (isCdmaMo()) { 1057 UserData uData = new UserData(); 1058 uData.payloadStr = message; 1059 uData.userDataHeader = smsHeader; 1060 if (encoding == SmsConstants.ENCODING_7BIT) { 1061 uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; 1062 } else { // assume UTF-16 1063 uData.msgEncoding = UserData.ENCODING_UNICODE_16; 1064 } 1065 uData.msgEncodingSet = true; 1066 1067 /* By setting the statusReportRequested bit only for the 1068 * last message fragment, this will result in only one 1069 * callback to the sender when that last fragment delivery 1070 * has been acknowledged. */ 1071 //TODO FIX 1072 SmsMessageBase.SubmitPduBase submitPdu = 1073 com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(destinationAddress, 1074 uData, (deliveryIntent != null) && lastPart, priority); 1075 1076 HashMap map = getSmsTrackerMap(destinationAddress, scAddress, 1077 message, submitPdu); 1078 return getSmsTracker(map, sentIntent, deliveryIntent, 1079 getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader, 1080 (!lastPart || expectMore), fullMessageText, true /*isText*/, 1081 true /*persistMessage*/, priority, validityPeriod); 1082 1083 } else { 1084 SmsMessageBase.SubmitPduBase pdu = 1085 com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, 1086 destinationAddress, message, deliveryIntent != null, 1087 SmsHeader.toByteArray(smsHeader), encoding, smsHeader.languageTable, 1088 smsHeader.languageShiftTable, validityPeriod); 1089 if (pdu != null) { 1090 HashMap map = getSmsTrackerMap(destinationAddress, scAddress, 1091 message, pdu); 1092 return getSmsTracker(map, sentIntent, 1093 deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri, 1094 smsHeader, (!lastPart || expectMore), fullMessageText, true /*isText*/, 1095 false /*persistMessage*/, priority, validityPeriod); 1096 } else { 1097 Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null"); 1098 return null; 1099 } 1100 } 1101 } 1102 1103 /** 1104 * Send an SMS 1105 * @param tracker will contain: 1106 * -smsc the SMSC to send the message through, or NULL for the 1107 * default SMSC 1108 * -pdu the raw PDU to send 1109 * -sentIntent if not NULL this <code>Intent</code> is 1110 * broadcast when the message is successfully sent, or failed. 1111 * The result code will be <code>Activity.RESULT_OK<code> for success, 1112 * or one of these errors: 1113 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 1114 * <code>RESULT_ERROR_RADIO_OFF</code> 1115 * <code>RESULT_ERROR_NULL_PDU</code> 1116 * <code>RESULT_ERROR_NO_SERVICE</code>. 1117 * The per-application based SMS control checks sentIntent. If sentIntent 1118 * is NULL the caller will be checked against all unknown applications, 1119 * which cause smaller number of SMS to be sent in checking period. 1120 * -deliveryIntent if not NULL this <code>Intent</code> is 1121 * broadcast when the message is delivered to the recipient. The 1122 * raw pdu of the status report is in the extended data ("pdu"). 1123 * -param destAddr the destination phone number (for short code confirmation) 1124 */ 1125 @VisibleForTesting 1126 public void sendRawPdu(SmsTracker tracker) { 1127 HashMap map = tracker.getData(); 1128 byte pdu[] = (byte[]) map.get(MAP_KEY_PDU); 1129 1130 if (mSmsSendDisabled) { 1131 Rlog.e(TAG, "Device does not support sending sms."); 1132 tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/); 1133 return; 1134 } 1135 1136 if (pdu == null) { 1137 Rlog.e(TAG, "Empty PDU"); 1138 tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/); 1139 return; 1140 } 1141 1142 // Get calling app package name via UID from Binder call 1143 PackageManager pm = mContext.getPackageManager(); 1144 String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid()); 1145 1146 if (packageNames == null || packageNames.length == 0) { 1147 // Refuse to send SMS if we can't get the calling package name. 1148 Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS"); 1149 tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/); 1150 return; 1151 } 1152 1153 // Get package info via packagemanager 1154 PackageInfo appInfo; 1155 try { 1156 // XXX this is lossy- apps can share a UID 1157 appInfo = pm.getPackageInfoAsUser( 1158 packageNames[0], PackageManager.GET_SIGNATURES, tracker.mUserId); 1159 } catch (PackageManager.NameNotFoundException e) { 1160 Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS"); 1161 tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/); 1162 return; 1163 } 1164 1165 // checkDestination() returns true if the destination is not a premium short code or the 1166 // sending app is approved to send to short codes. Otherwise, a message is sent to our 1167 // handler with the SmsTracker to request user confirmation before sending. 1168 if (checkDestination(tracker)) { 1169 // check for excessive outgoing SMS usage by this app 1170 if (!mSmsDispatchersController.getUsageMonitor().check( 1171 appInfo.packageName, SINGLE_PART_SMS)) { 1172 sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker)); 1173 return; 1174 } 1175 1176 sendSms(tracker); 1177 } 1178 1179 if (PhoneNumberUtils.isLocalEmergencyNumber(mContext, tracker.mDestAddress)) { 1180 new AsyncEmergencyContactNotifier(mContext).execute(); 1181 } 1182 } 1183 1184 /** 1185 * Check if destination is a potential premium short code and sender is not pre-approved to 1186 * send to short codes. 1187 * 1188 * @param tracker the tracker for the SMS to send 1189 * @return true if the destination is approved; false if user confirmation event was sent 1190 */ 1191 boolean checkDestination(SmsTracker tracker) { 1192 if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION) 1193 == PackageManager.PERMISSION_GRANTED) { 1194 return true; // app is pre-approved to send to short codes 1195 } else { 1196 int rule = mPremiumSmsRule.get(); 1197 int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE; 1198 if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) { 1199 String simCountryIso = mTelephonyManager.getSimCountryIso(); 1200 if (simCountryIso == null || simCountryIso.length() != 2) { 1201 Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso"); 1202 simCountryIso = mTelephonyManager.getNetworkCountryIso(); 1203 } 1204 1205 smsCategory = mSmsDispatchersController.getUsageMonitor().checkDestination( 1206 tracker.mDestAddress, simCountryIso); 1207 } 1208 if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) { 1209 String networkCountryIso = mTelephonyManager.getNetworkCountryIso(); 1210 if (networkCountryIso == null || networkCountryIso.length() != 2) { 1211 Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso"); 1212 networkCountryIso = mTelephonyManager.getSimCountryIso(); 1213 } 1214 1215 smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory, 1216 mSmsDispatchersController.getUsageMonitor().checkDestination( 1217 tracker.mDestAddress, networkCountryIso)); 1218 } 1219 1220 if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE 1221 || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE 1222 || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) { 1223 return true; // not a premium short code 1224 } 1225 1226 // Do not allow any premium sms during SuW 1227 if (Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0) { 1228 Rlog.e(TAG, "Can't send premium sms during Setup Wizard"); 1229 return false; 1230 } 1231 1232 // Wait for user confirmation unless the user has set permission to always allow/deny 1233 int premiumSmsPermission = 1234 mSmsDispatchersController.getUsageMonitor().getPremiumSmsPermission( 1235 tracker.getAppPackageName()); 1236 if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) { 1237 // First time trying to send to premium SMS. 1238 premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER; 1239 } 1240 1241 switch (premiumSmsPermission) { 1242 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW: 1243 Rlog.d(TAG, "User approved this app to send to premium SMS"); 1244 return true; 1245 1246 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW: 1247 Rlog.w(TAG, "User denied this app from sending to premium SMS"); 1248 Message msg = obtainMessage(EVENT_STOP_SENDING, tracker); 1249 msg.arg1 = ConfirmDialogListener.SHORT_CODE_MSG; 1250 msg.arg2 = ConfirmDialogListener.NEVER_ALLOW; 1251 sendMessage(msg); 1252 return false; // reject this message 1253 1254 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER: 1255 default: 1256 int event; 1257 if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) { 1258 event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE; 1259 } else { 1260 event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE; 1261 } 1262 sendMessage(obtainMessage(event, tracker)); 1263 return false; // wait for user confirmation 1264 } 1265 } 1266 } 1267 1268 /** 1269 * Deny sending an SMS if the outgoing queue limit is reached. Used when the message 1270 * must be confirmed by the user due to excessive usage or potential premium SMS detected. 1271 * @param tracker the SmsTracker for the message to send 1272 * @return true if the message was denied; false to continue with send confirmation 1273 */ 1274 private boolean denyIfQueueLimitReached(SmsTracker tracker) { 1275 if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) { 1276 // Deny sending message when the queue limit is reached. 1277 Rlog.e(TAG, "Denied because queue limit reached"); 1278 tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/); 1279 return true; 1280 } 1281 mPendingTrackerCount++; 1282 return false; 1283 } 1284 1285 /** 1286 * Returns the label for the specified app package name. 1287 * @param appPackage the package name of the app requesting to send an SMS 1288 * @return the label for the specified app, or the package name if getApplicationInfo() fails 1289 */ 1290 private CharSequence getAppLabel(String appPackage, @UserIdInt int userId) { 1291 PackageManager pm = mContext.getPackageManager(); 1292 try { 1293 ApplicationInfo appInfo = pm.getApplicationInfoAsUser(appPackage, 0, userId); 1294 return appInfo.loadSafeLabel(pm); 1295 } catch (PackageManager.NameNotFoundException e) { 1296 Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage); 1297 return appPackage; // fall back to package name if we can't get app label 1298 } 1299 } 1300 1301 /** 1302 * Post an alert when SMS needs confirmation due to excessive usage. 1303 * @param tracker an SmsTracker for the current message. 1304 */ 1305 protected void handleReachSentLimit(SmsTracker tracker) { 1306 if (denyIfQueueLimitReached(tracker)) { 1307 return; // queue limit reached; error was returned to caller 1308 } 1309 1310 CharSequence appLabel = getAppLabel(tracker.getAppPackageName(), tracker.mUserId); 1311 Resources r = Resources.getSystem(); 1312 Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel)); 1313 1314 // Construct ConfirmDialogListenter for Rate Limit handling 1315 ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null, 1316 ConfirmDialogListener.RATE_LIMIT); 1317 1318 AlertDialog d = new AlertDialog.Builder(mContext) 1319 .setTitle(R.string.sms_control_title) 1320 .setIcon(R.drawable.stat_sys_warning) 1321 .setMessage(messageText) 1322 .setPositiveButton(r.getString(R.string.sms_control_yes), listener) 1323 .setNegativeButton(r.getString(R.string.sms_control_no), listener) 1324 .setOnCancelListener(listener) 1325 .create(); 1326 1327 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1328 d.show(); 1329 } 1330 1331 /** 1332 * Post an alert for user confirmation when sending to a potential short code. 1333 * @param isPremium true if the destination is known to be a premium short code 1334 * @param tracker the SmsTracker for the current message. 1335 */ 1336 protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) { 1337 if (denyIfQueueLimitReached(tracker)) { 1338 return; // queue limit reached; error was returned to caller 1339 } 1340 1341 int detailsId; 1342 if (isPremium) { 1343 detailsId = R.string.sms_premium_short_code_details; 1344 } else { 1345 detailsId = R.string.sms_short_code_details; 1346 } 1347 1348 CharSequence appLabel = getAppLabel(tracker.getAppPackageName(), tracker.mUserId); 1349 Resources r = Resources.getSystem(); 1350 Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message, 1351 appLabel, tracker.mDestAddress)); 1352 1353 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( 1354 Context.LAYOUT_INFLATER_SERVICE); 1355 View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null); 1356 1357 // Construct ConfirmDialogListenter for short code message sending 1358 ConfirmDialogListener listener = new ConfirmDialogListener(tracker, 1359 (TextView) layout.findViewById(R.id.sms_short_code_remember_undo_instruction), 1360 ConfirmDialogListener.SHORT_CODE_MSG); 1361 1362 1363 TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message); 1364 messageView.setText(messageText); 1365 1366 ViewGroup detailsLayout = (ViewGroup) layout.findViewById( 1367 R.id.sms_short_code_detail_layout); 1368 TextView detailsView = (TextView) detailsLayout.findViewById( 1369 R.id.sms_short_code_detail_message); 1370 detailsView.setText(detailsId); 1371 1372 CheckBox rememberChoice = (CheckBox) layout.findViewById( 1373 R.id.sms_short_code_remember_choice_checkbox); 1374 rememberChoice.setOnCheckedChangeListener(listener); 1375 1376 AlertDialog d = new AlertDialog.Builder(mContext) 1377 .setView(layout) 1378 .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener) 1379 .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener) 1380 .setOnCancelListener(listener) 1381 .create(); 1382 1383 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1384 d.show(); 1385 1386 listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE)); 1387 listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE)); 1388 } 1389 1390 /** 1391 * Send the message along to the radio. 1392 * 1393 * @param tracker holds the SMS message to send 1394 */ 1395 protected abstract void sendSms(SmsTracker tracker); 1396 1397 /** 1398 * Retry the message along to the radio. 1399 * 1400 * @param tracker holds the SMS message to send 1401 */ 1402 public void sendRetrySms(SmsTracker tracker) { 1403 // re-routing to SmsDispatchersController 1404 if (mSmsDispatchersController != null) { 1405 mSmsDispatchersController.sendRetrySms(tracker); 1406 } else { 1407 Rlog.e(TAG, mSmsDispatchersController + " is null. Retry failed"); 1408 } 1409 } 1410 1411 /** 1412 * Send the multi-part SMS based on multipart Sms tracker 1413 * 1414 * @param tracker holds the multipart Sms tracker ready to be sent 1415 */ 1416 private void sendMultipartSms(SmsTracker tracker) { 1417 ArrayList<String> parts; 1418 ArrayList<PendingIntent> sentIntents; 1419 ArrayList<PendingIntent> deliveryIntents; 1420 1421 HashMap<String, Object> map = tracker.getData(); 1422 1423 String destinationAddress = (String) map.get("destination"); 1424 String scAddress = (String) map.get("scaddress"); 1425 1426 parts = (ArrayList<String>) map.get("parts"); 1427 sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents"); 1428 deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents"); 1429 1430 // check if in service 1431 int ss = mPhone.getServiceState().getState(); 1432 // if sms over IMS is not supported on data and voice is not available... 1433 if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { 1434 for (int i = 0, count = parts.size(); i < count; i++) { 1435 PendingIntent sentIntent = null; 1436 if (sentIntents != null && sentIntents.size() > i) { 1437 sentIntent = sentIntents.get(i); 1438 } 1439 handleNotInService(ss, sentIntent); 1440 } 1441 return; 1442 } 1443 1444 sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents, 1445 null/*messageUri*/, null/*callingPkg*/, tracker.mPersistMessage, tracker.mPriority, 1446 tracker.mExpectMore, tracker.mValidityPeriod); 1447 } 1448 1449 /** 1450 * Keeps track of an SMS that has been sent to the RIL, until it has 1451 * successfully been sent, or we're done trying. 1452 */ 1453 public static class SmsTracker { 1454 // fields need to be public for derived SmsDispatchers 1455 private final HashMap<String, Object> mData; 1456 public int mRetryCount; 1457 // IMS retry counter. Nonzero indicates initial message was sent over IMS channel in RIL and 1458 // counts how many retries have been made on the IMS channel. 1459 // Used in older implementations where the message is sent over IMS using the RIL. 1460 public int mImsRetry; 1461 // Tag indicating that this SMS is being handled by the ImsSmsDispatcher. This tracker 1462 // should not try to use SMS over IMS over the RIL interface in this case when falling back. 1463 public boolean mUsesImsServiceForIms; 1464 public int mMessageRef; 1465 public boolean mExpectMore; 1466 public int mValidityPeriod; 1467 public int mPriority; 1468 String mFormat; 1469 1470 public final PendingIntent mSentIntent; 1471 public final PendingIntent mDeliveryIntent; 1472 1473 public final PackageInfo mAppInfo; 1474 public final String mDestAddress; 1475 1476 public final SmsHeader mSmsHeader; 1477 1478 private long mTimestamp = System.currentTimeMillis(); 1479 public Uri mMessageUri; // Uri of persisted message if we wrote one 1480 1481 // Reference to states of a multipart message that this part belongs to 1482 private AtomicInteger mUnsentPartCount; 1483 private AtomicBoolean mAnyPartFailed; 1484 // The full message content of a single part message 1485 // or a multipart message that this part belongs to 1486 private String mFullMessageText; 1487 1488 private int mSubId; 1489 1490 // If this is a text message (instead of data message) 1491 private boolean mIsText; 1492 1493 private boolean mPersistMessage; 1494 1495 // User who sends the SMS. 1496 private final @UserIdInt int mUserId; 1497 1498 private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, 1499 PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format, 1500 AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, 1501 SmsHeader smsHeader, boolean expectMore, String fullMessageText, int subId, 1502 boolean isText, boolean persistMessage, int userId, int priority, 1503 int validityPeriod) { 1504 mData = data; 1505 mSentIntent = sentIntent; 1506 mDeliveryIntent = deliveryIntent; 1507 mRetryCount = 0; 1508 mAppInfo = appInfo; 1509 mDestAddress = destAddr; 1510 mFormat = format; 1511 mExpectMore = expectMore; 1512 mImsRetry = 0; 1513 mUsesImsServiceForIms = false; 1514 mMessageRef = 0; 1515 mUnsentPartCount = unsentPartCount; 1516 mAnyPartFailed = anyPartFailed; 1517 mMessageUri = messageUri; 1518 mSmsHeader = smsHeader; 1519 mFullMessageText = fullMessageText; 1520 mSubId = subId; 1521 mIsText = isText; 1522 mPersistMessage = persistMessage; 1523 mUserId = userId; 1524 mPriority = priority; 1525 mValidityPeriod = validityPeriod; 1526 } 1527 1528 /** 1529 * Returns whether this tracker holds a multi-part SMS. 1530 * @return true if the tracker holds a multi-part SMS; false otherwise 1531 */ 1532 boolean isMultipart() { 1533 return mData.containsKey("parts"); 1534 } 1535 1536 public HashMap<String, Object> getData() { 1537 return mData; 1538 } 1539 1540 /** 1541 * Get the App package name 1542 * @return App package name info 1543 */ 1544 public String getAppPackageName() { 1545 return mAppInfo != null ? mAppInfo.packageName : null; 1546 } 1547 1548 /** 1549 * Update the status of this message if we persisted it 1550 */ 1551 public void updateSentMessageStatus(Context context, int status) { 1552 if (mMessageUri != null) { 1553 // If we wrote this message in writeSentMessage, update it now 1554 ContentValues values = new ContentValues(1); 1555 values.put(Sms.STATUS, status); 1556 SqliteWrapper.update(context, context.getContentResolver(), 1557 mMessageUri, values, null, null); 1558 } 1559 } 1560 1561 /** 1562 * Set the final state of a message: FAILED or SENT 1563 * 1564 * @param context The Context 1565 * @param messageType The final message type 1566 * @param errorCode The error code 1567 */ 1568 private void updateMessageState(Context context, int messageType, int errorCode) { 1569 if (mMessageUri == null) { 1570 return; 1571 } 1572 final ContentValues values = new ContentValues(2); 1573 values.put(Sms.TYPE, messageType); 1574 values.put(Sms.ERROR_CODE, errorCode); 1575 final long identity = Binder.clearCallingIdentity(); 1576 try { 1577 if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values, 1578 null/*where*/, null/*selectionArgs*/) != 1) { 1579 Rlog.e(TAG, "Failed to move message to " + messageType); 1580 } 1581 } finally { 1582 Binder.restoreCallingIdentity(identity); 1583 } 1584 } 1585 1586 /** 1587 * Persist a sent SMS if required: 1588 * 1. It is a text message 1589 * 2. SmsApplication tells us to persist: sent from apps that are not default-SMS app or 1590 * bluetooth 1591 * 1592 * @param context 1593 * @param messageType The folder to store (FAILED or SENT) 1594 * @param errorCode The current error code for this SMS or SMS part 1595 * @return The telephony provider URI if stored 1596 */ 1597 private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) { 1598 if (!mIsText || !mPersistMessage || 1599 !SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) { 1600 return null; 1601 } 1602 Rlog.d(TAG, "Persist SMS into " 1603 + (messageType == Sms.MESSAGE_TYPE_FAILED ? "FAILED" : "SENT")); 1604 final ContentValues values = new ContentValues(); 1605 values.put(Sms.SUBSCRIPTION_ID, mSubId); 1606 values.put(Sms.ADDRESS, mDestAddress); 1607 values.put(Sms.BODY, mFullMessageText); 1608 values.put(Sms.DATE, System.currentTimeMillis()); // milliseconds 1609 values.put(Sms.SEEN, 1); 1610 values.put(Sms.READ, 1); 1611 final String creator = mAppInfo != null ? mAppInfo.packageName : null; 1612 if (!TextUtils.isEmpty(creator)) { 1613 values.put(Sms.CREATOR, creator); 1614 } 1615 if (mDeliveryIntent != null) { 1616 values.put(Sms.STATUS, Telephony.Sms.STATUS_PENDING); 1617 } 1618 if (errorCode != 0) { 1619 values.put(Sms.ERROR_CODE, errorCode); 1620 } 1621 final long identity = Binder.clearCallingIdentity(); 1622 final ContentResolver resolver = context.getContentResolver(); 1623 try { 1624 final Uri uri = resolver.insert(Telephony.Sms.Sent.CONTENT_URI, values); 1625 if (uri != null && messageType == Sms.MESSAGE_TYPE_FAILED) { 1626 // Since we can't persist a message directly into FAILED box, 1627 // we have to update the column after we persist it into SENT box. 1628 // The gap between the state change is tiny so I would not expect 1629 // it to cause any serious problem 1630 // TODO: we should add a "failed" URI for this in SmsProvider? 1631 final ContentValues updateValues = new ContentValues(1); 1632 updateValues.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED); 1633 resolver.update(uri, updateValues, null/*where*/, null/*selectionArgs*/); 1634 } 1635 return uri; 1636 } catch (Exception e) { 1637 Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e); 1638 return null; 1639 } finally { 1640 Binder.restoreCallingIdentity(identity); 1641 } 1642 } 1643 1644 /** 1645 * Persist or update an SMS depending on if we send a new message or a stored message 1646 * 1647 * @param context 1648 * @param messageType The message folder for this SMS, FAILED or SENT 1649 * @param errorCode The current error code for this SMS or SMS part 1650 */ 1651 private void persistOrUpdateMessage(Context context, int messageType, int errorCode) { 1652 if (mMessageUri != null) { 1653 updateMessageState(context, messageType, errorCode); 1654 } else { 1655 mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode); 1656 } 1657 } 1658 1659 /** 1660 * Handle a failure of a single part message or a part of a multipart message 1661 * 1662 * @param context The Context 1663 * @param error The error to send back with 1664 * @param errorCode 1665 */ 1666 public void onFailed(Context context, int error, int errorCode) { 1667 if (mAnyPartFailed != null) { 1668 mAnyPartFailed.set(true); 1669 } 1670 // is single part or last part of multipart message 1671 boolean isSinglePartOrLastPart = true; 1672 if (mUnsentPartCount != null) { 1673 isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0; 1674 } 1675 if (isSinglePartOrLastPart) { 1676 persistOrUpdateMessage(context, Sms.MESSAGE_TYPE_FAILED, errorCode); 1677 } 1678 if (mSentIntent != null) { 1679 try { 1680 // Extra information to send with the sent intent 1681 Intent fillIn = new Intent(); 1682 if (mMessageUri != null) { 1683 // Pass this to SMS apps so that they know where it is stored 1684 fillIn.putExtra("uri", mMessageUri.toString()); 1685 } 1686 if (errorCode != 0) { 1687 fillIn.putExtra("errorCode", errorCode); 1688 } 1689 if (mUnsentPartCount != null && isSinglePartOrLastPart) { 1690 // Is multipart and last part 1691 fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true); 1692 } 1693 mSentIntent.send(context, error, fillIn); 1694 } catch (CanceledException ex) { 1695 Rlog.e(TAG, "Failed to send result"); 1696 } 1697 } 1698 } 1699 1700 /** 1701 * Handle the sent of a single part message or a part of a multipart message 1702 * 1703 * @param context The Context 1704 */ 1705 public void onSent(Context context) { 1706 // is single part or last part of multipart message 1707 boolean isSinglePartOrLastPart = true; 1708 if (mUnsentPartCount != null) { 1709 isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0; 1710 } 1711 if (isSinglePartOrLastPart) { 1712 int messageType = Sms.MESSAGE_TYPE_SENT; 1713 if (mAnyPartFailed != null && mAnyPartFailed.get()) { 1714 messageType = Sms.MESSAGE_TYPE_FAILED; 1715 } 1716 persistOrUpdateMessage(context, messageType, 0/*errorCode*/); 1717 } 1718 if (mSentIntent != null) { 1719 try { 1720 // Extra information to send with the sent intent 1721 Intent fillIn = new Intent(); 1722 if (mMessageUri != null) { 1723 // Pass this to SMS apps so that they know where it is stored 1724 fillIn.putExtra("uri", mMessageUri.toString()); 1725 } 1726 if (mUnsentPartCount != null && isSinglePartOrLastPart) { 1727 // Is multipart and last part 1728 fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true); 1729 } 1730 mSentIntent.send(context, Activity.RESULT_OK, fillIn); 1731 } catch (CanceledException ex) { 1732 Rlog.e(TAG, "Failed to send result"); 1733 } 1734 } 1735 } 1736 } 1737 1738 protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, 1739 PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount, 1740 AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader, 1741 boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, 1742 int priority, int validityPeriod) { 1743 // Get calling app package name via UID from Binder call 1744 PackageManager pm = mContext.getPackageManager(); 1745 String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid()); 1746 1747 // Get package info via packagemanager 1748 final int userId = UserHandle.getCallingUserId(); 1749 PackageInfo appInfo = null; 1750 if (packageNames != null && packageNames.length > 0) { 1751 try { 1752 // XXX this is lossy- apps can share a UID 1753 appInfo = pm.getPackageInfoAsUser( 1754 packageNames[0], PackageManager.GET_SIGNATURES, userId); 1755 } catch (PackageManager.NameNotFoundException e) { 1756 // error will be logged in sendRawPdu 1757 } 1758 } 1759 // Strip non-digits from destination phone number before checking for short codes 1760 // and before displaying the number to the user if confirmation is required. 1761 String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr")); 1762 return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format, 1763 unsentPartCount, anyPartFailed, messageUri, smsHeader, expectMore, 1764 fullMessageText, getSubId(), isText, persistMessage, userId, priority, 1765 validityPeriod); 1766 } 1767 1768 protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, 1769 PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore, 1770 String fullMessageText, boolean isText, boolean persistMessage) { 1771 return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/, 1772 null/*anyPartFailed*/, messageUri, null/*smsHeader*/, expectMore, 1773 fullMessageText, isText, persistMessage, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, 1774 SMS_MESSAGE_PERIOD_NOT_SPECIFIED); 1775 } 1776 1777 protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, 1778 PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore, 1779 String fullMessageText, boolean isText, boolean persistMessage, int priority, 1780 int validityPeriod) { 1781 return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/, 1782 null/*anyPartFailed*/, messageUri, null/*smsHeader*/, expectMore, fullMessageText, 1783 isText, persistMessage, priority, validityPeriod); 1784 } 1785 1786 protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr, 1787 String text, SmsMessageBase.SubmitPduBase pdu) { 1788 HashMap<String, Object> map = new HashMap<String, Object>(); 1789 map.put(MAP_KEY_DEST_ADDR, destAddr); 1790 map.put(MAP_KEY_SC_ADDR, scAddr); 1791 map.put(MAP_KEY_TEXT, text); 1792 map.put(MAP_KEY_SMSC, pdu.encodedScAddress); 1793 map.put(MAP_KEY_PDU, pdu.encodedMessage); 1794 return map; 1795 } 1796 1797 protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr, 1798 int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) { 1799 HashMap<String, Object> map = new HashMap<String, Object>(); 1800 map.put(MAP_KEY_DEST_ADDR, destAddr); 1801 map.put(MAP_KEY_SC_ADDR, scAddr); 1802 map.put(MAP_KEY_DEST_PORT, destPort); 1803 map.put(MAP_KEY_DATA, data); 1804 map.put(MAP_KEY_SMSC, pdu.encodedScAddress); 1805 map.put(MAP_KEY_PDU, pdu.encodedMessage); 1806 return map; 1807 } 1808 1809 /** 1810 * Dialog listener for SMS confirmation dialog. 1811 */ 1812 private final class ConfirmDialogListener 1813 implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener, 1814 CompoundButton.OnCheckedChangeListener { 1815 1816 private final SmsTracker mTracker; 1817 private Button mPositiveButton; 1818 private Button mNegativeButton; 1819 private boolean mRememberChoice; // default is unchecked 1820 private final TextView mRememberUndoInstruction; 1821 private int mConfirmationType; // 0 - Short Code Msg Sending; 1 - Rate Limit Exceeded 1822 private static final int SHORT_CODE_MSG = 0; // Short Code Msg 1823 private static final int RATE_LIMIT = 1; // Rate Limit Exceeded 1824 private static final int NEVER_ALLOW = 1; // Never Allow 1825 1826 ConfirmDialogListener(SmsTracker tracker, TextView textView, int confirmationType) { 1827 mTracker = tracker; 1828 mRememberUndoInstruction = textView; 1829 mConfirmationType = confirmationType; 1830 } 1831 1832 void setPositiveButton(Button button) { 1833 mPositiveButton = button; 1834 } 1835 1836 void setNegativeButton(Button button) { 1837 mNegativeButton = button; 1838 } 1839 1840 @Override 1841 public void onClick(DialogInterface dialog, int which) { 1842 // Always set the SMS permission so that Settings will show a permission setting 1843 // for the app (it won't be shown until after the app tries to send to a short code). 1844 int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER; 1845 1846 if (which == DialogInterface.BUTTON_POSITIVE) { 1847 Rlog.d(TAG, "CONFIRM sending SMS"); 1848 // XXX this is lossy- apps can have more than one signature 1849 EventLog.writeEvent(EventLogTags.EXP_DET_SMS_SENT_BY_USER, 1850 mTracker.mAppInfo.applicationInfo == null ? 1851 -1 : mTracker.mAppInfo.applicationInfo.uid); 1852 sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker)); 1853 if (mRememberChoice) { 1854 newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW; 1855 } 1856 } else if (which == DialogInterface.BUTTON_NEGATIVE) { 1857 Rlog.d(TAG, "DENY sending SMS"); 1858 // XXX this is lossy- apps can have more than one signature 1859 EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER, 1860 mTracker.mAppInfo.applicationInfo == null ? 1861 -1 : mTracker.mAppInfo.applicationInfo.uid); 1862 Message msg = obtainMessage(EVENT_STOP_SENDING, mTracker); 1863 msg.arg1 = mConfirmationType; 1864 if (mRememberChoice) { 1865 newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW; 1866 msg.arg2 = ConfirmDialogListener.NEVER_ALLOW; 1867 } 1868 sendMessage(msg); 1869 } 1870 mSmsDispatchersController.setPremiumSmsPermission(mTracker.getAppPackageName(), 1871 newSmsPermission); 1872 } 1873 1874 @Override 1875 public void onCancel(DialogInterface dialog) { 1876 Rlog.d(TAG, "dialog dismissed: don't send SMS"); 1877 Message msg = obtainMessage(EVENT_STOP_SENDING, mTracker); 1878 msg.arg1 = mConfirmationType; 1879 sendMessage(msg); 1880 } 1881 1882 @Override 1883 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 1884 Rlog.d(TAG, "remember this choice: " + isChecked); 1885 mRememberChoice = isChecked; 1886 if (isChecked) { 1887 mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow); 1888 mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow); 1889 if (mRememberUndoInstruction != null) { 1890 mRememberUndoInstruction. 1891 setText(R.string.sms_short_code_remember_undo_instruction); 1892 mRememberUndoInstruction.setPadding(0,0,0,32); 1893 } 1894 } else { 1895 mPositiveButton.setText(R.string.sms_short_code_confirm_allow); 1896 mNegativeButton.setText(R.string.sms_short_code_confirm_deny); 1897 if (mRememberUndoInstruction != null) { 1898 mRememberUndoInstruction.setText(""); 1899 mRememberUndoInstruction.setPadding(0,0,0,0); 1900 } 1901 } 1902 } 1903 } 1904 1905 public boolean isIms() { 1906 if (mSmsDispatchersController != null) { 1907 return mSmsDispatchersController.isIms(); 1908 } else { 1909 Rlog.e(TAG, "mSmsDispatchersController is null"); 1910 return false; 1911 } 1912 } 1913 1914 private String getMultipartMessageText(ArrayList<String> parts) { 1915 final StringBuilder sb = new StringBuilder(); 1916 for (String part : parts) { 1917 if (part != null) { 1918 sb.append(part); 1919 } 1920 } 1921 return sb.toString(); 1922 } 1923 1924 protected String getCarrierAppPackageName() { 1925 UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId()); 1926 if (card == null) { 1927 return null; 1928 } 1929 1930 List<String> carrierPackages = card.getCarrierPackageNamesForIntent( 1931 mContext.getPackageManager(), new Intent(CarrierMessagingService.SERVICE_INTERFACE)); 1932 if (carrierPackages != null && carrierPackages.size() == 1) { 1933 return carrierPackages.get(0); 1934 } 1935 // If there is no carrier package which implements CarrierMessagingService, then lookup if 1936 // for a carrierImsPackage that implements CarrierMessagingService. 1937 return CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone, 1938 new Intent(CarrierMessagingService.SERVICE_INTERFACE)); 1939 } 1940 1941 protected int getSubId() { 1942 return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.getPhoneId()); 1943 } 1944 1945 private void checkCallerIsPhoneOrCarrierApp() { 1946 int uid = Binder.getCallingUid(); 1947 int appId = UserHandle.getAppId(uid); 1948 if (appId == Process.PHONE_UID || uid == 0) { 1949 return; 1950 } 1951 try { 1952 PackageManager pm = mContext.getPackageManager(); 1953 ApplicationInfo ai = pm.getApplicationInfo(getCarrierAppPackageName(), 0); 1954 if (!UserHandle.isSameApp(ai.uid, Binder.getCallingUid())) { 1955 throw new SecurityException("Caller is not phone or carrier app!"); 1956 } 1957 } catch (PackageManager.NameNotFoundException re) { 1958 throw new SecurityException("Caller is not phone or carrier app!"); 1959 } 1960 } 1961 1962 protected boolean isCdmaMo() { 1963 return mSmsDispatchersController.isCdmaMo(); 1964 } 1965 } 1966