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