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