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