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