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