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