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