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