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 com.android.internal.telephony.SmsResponse.NO_ERROR_CODE; 20 import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE; 21 import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.app.Activity; 26 import android.app.PendingIntent; 27 import android.app.PendingIntent.CanceledException; 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.net.Uri; 33 import android.os.AsyncResult; 34 import android.os.Binder; 35 import android.os.Handler; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.UserManager; 39 import android.provider.Telephony.Sms; 40 import android.provider.Telephony.Sms.Intents; 41 import android.telephony.Annotation.DisconnectCauses; 42 import android.telephony.DomainSelectionService; 43 import android.telephony.NetworkRegistrationInfo; 44 import android.telephony.ServiceState; 45 import android.telephony.SmsManager; 46 import android.telephony.SmsMessage; 47 import android.telephony.TelephonyManager; 48 import android.text.TextUtils; 49 50 import com.android.ims.ImsManager; 51 import com.android.internal.annotations.VisibleForTesting; 52 import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; 53 import com.android.internal.telephony.cdma.CdmaSMSDispatcher; 54 import com.android.internal.telephony.domainselection.DomainSelectionConnection; 55 import com.android.internal.telephony.domainselection.DomainSelectionResolver; 56 import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection; 57 import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection; 58 import com.android.internal.telephony.gsm.GsmInboundSmsHandler; 59 import com.android.internal.telephony.gsm.GsmSMSDispatcher; 60 import com.android.telephony.Rlog; 61 62 import java.io.FileDescriptor; 63 import java.io.PrintWriter; 64 import java.util.ArrayList; 65 import java.util.HashMap; 66 import java.util.List; 67 import java.util.concurrent.CompletableFuture; 68 69 /** 70 * 71 */ 72 public class SmsDispatchersController extends Handler { 73 private static final String TAG = "SmsDispatchersController"; 74 private static final boolean VDBG = false; // STOPSHIP if true 75 76 /** Radio is ON */ 77 private static final int EVENT_RADIO_ON = 11; 78 79 /** IMS registration/SMS format changed */ 80 private static final int EVENT_IMS_STATE_CHANGED = 12; 81 82 /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */ 83 private static final int EVENT_IMS_STATE_DONE = 13; 84 85 /** Service state changed */ 86 private static final int EVENT_SERVICE_STATE_CHANGED = 14; 87 88 /** Purge old message segments */ 89 private static final int EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY = 15; 90 91 /** User unlocked the device */ 92 private static final int EVENT_USER_UNLOCKED = 16; 93 94 /** InboundSmsHandler exited WaitingState */ 95 protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17; 96 97 /** Delete any partial message segments after being IN_SERVICE for 1 day. */ 98 private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24; 99 /** Constant for invalid time */ 100 private static final long INVALID_TIME = -1; 101 /** Time at which last IN_SERVICE event was received */ 102 private long mLastInServiceTime = INVALID_TIME; 103 /** Current IN_SERVICE duration */ 104 private long mCurrentWaitElapsedDuration = 0; 105 /** Time at which the current PARTIAL_SEGMENT_WAIT_DURATION timer was started */ 106 private long mCurrentWaitStartTime = INVALID_TIME; 107 108 private SMSDispatcher mCdmaDispatcher; 109 private SMSDispatcher mGsmDispatcher; 110 private ImsSmsDispatcher mImsSmsDispatcher; 111 112 private GsmInboundSmsHandler mGsmInboundSmsHandler; 113 private CdmaInboundSmsHandler mCdmaInboundSmsHandler; 114 115 private Phone mPhone; 116 /** Outgoing message counter. Shared by all dispatchers. */ 117 private final SmsUsageMonitor mUsageMonitor; 118 private final CommandsInterface mCi; 119 private final Context mContext; 120 121 /** true if IMS is registered and sms is supported, false otherwise.*/ 122 private boolean mIms = false; 123 private String mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN; 124 125 /** 3GPP format sent messages awaiting a delivery status report. */ 126 private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP = new HashMap<>(); 127 128 /** 3GPP2 format sent messages awaiting a delivery status report. */ 129 private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP2 = 130 new HashMap<>(); 131 132 /** 133 * Testing interface for injecting mock DomainSelectionConnection and a flag to indicate 134 * whether the domain selection is supported. 135 */ 136 @VisibleForTesting 137 public interface DomainSelectionResolverProxy { 138 /** 139 * Returns a {@link DomainSelectionConnection} created using the specified 140 * context and callback. 141 * 142 * @param phone The {@link Phone} instance. 143 * @param selectorType The domain selector type to identify the domain selection connection. 144 * A {@link DomainSelectionService#SELECTOR_TYPE_SMS} is used for SMS. 145 * @param isEmergency A flag to indicate whether this connection is 146 * for an emergency SMS or not. 147 */ getDomainSelectionConnection(Phone phone, @DomainSelectionService.SelectorType int selectorType, boolean isEmergency)148 @Nullable DomainSelectionConnection getDomainSelectionConnection(Phone phone, 149 @DomainSelectionService.SelectorType int selectorType, boolean isEmergency); 150 151 /** 152 * Checks if the device supports the domain selection service to route the call / SMS / 153 * supplementary services to the appropriate domain. 154 * 155 * @return {@code true} if the domain selection is supported on the device, 156 * {@code false} otherwise. 157 */ isDomainSelectionSupported()158 boolean isDomainSelectionSupported(); 159 } 160 161 private DomainSelectionResolverProxy mDomainSelectionResolverProxy = 162 new DomainSelectionResolverProxy() { 163 @Override 164 @Nullable 165 public DomainSelectionConnection getDomainSelectionConnection(Phone phone, 166 @DomainSelectionService.SelectorType int selectorType, 167 boolean isEmergency) { 168 try { 169 return DomainSelectionResolver.getInstance().getDomainSelectionConnection( 170 phone, selectorType, isEmergency); 171 } catch (IllegalStateException e) { 172 // In general, DomainSelectionResolver is always initialized by TeleService, 173 // but if it's not initialized (like in unit tests), 174 // it returns null to perform the legacy behavior in this case. 175 return null; 176 } 177 } 178 179 @Override 180 public boolean isDomainSelectionSupported() { 181 return DomainSelectionResolver.getInstance().isDomainSelectionSupported(); 182 } 183 }; 184 185 /** Stores the sending SMS information for a pending request. */ 186 private class PendingRequest { 187 public static final int TYPE_DATA = 1; 188 public static final int TYPE_TEXT = 2; 189 public static final int TYPE_MULTIPART_TEXT = 3; 190 public static final int TYPE_RETRY_SMS = 4; 191 192 public final int type; 193 public final SMSDispatcher.SmsTracker tracker; 194 public final String callingPackage; 195 public final String destAddr; 196 public final String scAddr; 197 public final ArrayList<PendingIntent> sentIntents; 198 public final ArrayList<PendingIntent> deliveryIntents; 199 public final boolean isForVvm; 200 // sendData specific 201 public final byte[] data; 202 public final int destPort; 203 // sendText / sendMultipartText specific 204 public final ArrayList<String> texts; 205 public final Uri messageUri; 206 public final boolean persistMessage; 207 public final int priority; 208 public final boolean expectMore; 209 public final int validityPeriod; 210 public final long messageId; 211 public final boolean skipShortCodeCheck; 212 PendingRequest(int type, SMSDispatcher.SmsTracker tracker, String callingPackage, String destAddr, String scAddr, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, boolean isForVvm, byte[] data, int destPort, ArrayList<String> texts, Uri messageUri, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId, boolean skipShortCodeCheck)213 PendingRequest(int type, SMSDispatcher.SmsTracker tracker, String callingPackage, 214 String destAddr, String scAddr, ArrayList<PendingIntent> sentIntents, 215 ArrayList<PendingIntent> deliveryIntents, boolean isForVvm, byte[] data, 216 int destPort, ArrayList<String> texts, Uri messageUri, boolean persistMessage, 217 int priority, boolean expectMore, int validityPeriod, long messageId, 218 boolean skipShortCodeCheck) { 219 this.type = type; 220 this.tracker = tracker; 221 this.callingPackage = callingPackage; 222 this.destAddr = destAddr; 223 this.scAddr = scAddr; 224 this.sentIntents = sentIntents; 225 this.deliveryIntents = deliveryIntents; 226 this.isForVvm = isForVvm; 227 228 this.data = data; 229 this.destPort = destPort; 230 231 this.texts = texts; 232 this.messageUri = messageUri; 233 this.persistMessage = persistMessage; 234 this.priority = priority; 235 this.expectMore = expectMore; 236 this.validityPeriod = validityPeriod; 237 this.messageId = messageId; 238 this.skipShortCodeCheck = skipShortCodeCheck; 239 } 240 } 241 242 /** 243 * Manages the {@link DomainSelectionConnection} instance and its related information. 244 */ 245 @VisibleForTesting 246 protected class DomainSelectionConnectionHolder 247 implements DomainSelectionConnection.DomainSelectionConnectionCallback { 248 private final boolean mEmergency; 249 // Manages the pending request while selecting a proper domain. 250 private final List<PendingRequest> mPendingRequests = new ArrayList<>(); 251 // Manages the domain selection connections: MO SMS or emergency SMS. 252 private DomainSelectionConnection mConnection; 253 DomainSelectionConnectionHolder(boolean emergency)254 DomainSelectionConnectionHolder(boolean emergency) { 255 mEmergency = emergency; 256 } 257 258 /** 259 * Returns a {@link DomainSelectionConnection} instance. 260 */ getConnection()261 public DomainSelectionConnection getConnection() { 262 return mConnection; 263 } 264 265 /** 266 * Returns a list of {@link PendingRequest} that was added 267 * while the domain selection is performed. 268 */ getPendingRequests()269 public List<PendingRequest> getPendingRequests() { 270 return mPendingRequests; 271 } 272 273 /** 274 * Checks whether or not the domain selection is requested. 275 * If there is no pending request, the domain selection request is needed to 276 * select a proper domain for MO SMS. 277 */ isDomainSelectionRequested()278 public boolean isDomainSelectionRequested() { 279 return !mPendingRequests.isEmpty(); 280 } 281 282 /** 283 * Checks whether or not this holder is for an emergency SMS. 284 */ isEmergency()285 public boolean isEmergency() { 286 return mEmergency; 287 } 288 289 /** 290 * Clears all pending requests. 291 */ clearAllRequests()292 public void clearAllRequests() { 293 mPendingRequests.clear(); 294 } 295 296 /** 297 * Add a new pending request. 298 */ addRequest(@onNull PendingRequest request)299 public void addRequest(@NonNull PendingRequest request) { 300 mPendingRequests.add(request); 301 } 302 303 /** 304 * Sets a {@link DomainSelectionConnection} instance. 305 */ setConnection(DomainSelectionConnection connection)306 public void setConnection(DomainSelectionConnection connection) { 307 mConnection = connection; 308 } 309 310 311 @Override onSelectionTerminated(@isconnectCauses int cause)312 public void onSelectionTerminated(@DisconnectCauses int cause) { 313 notifyDomainSelectionTerminated(this); 314 } 315 } 316 317 /** Manages the domain selection connections: MO SMS or emergency SMS. */ 318 private DomainSelectionConnectionHolder mDscHolder; 319 private DomainSelectionConnectionHolder mEmergencyDscHolder; 320 321 /** 322 * Puts a delivery pending tracker to the map based on the format. 323 * 324 * @param tracker the tracker awaiting a delivery status report. 325 */ putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker)326 public void putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker) { 327 if (isCdmaFormat(tracker.mFormat)) { 328 mDeliveryPendingMapFor3GPP2.put(tracker.mMessageRef, tracker); 329 } else { 330 mDeliveryPendingMapFor3GPP.put(tracker.mMessageRef, tracker); 331 } 332 } 333 SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor)334 public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, 335 SmsUsageMonitor usageMonitor) { 336 this(phone, storageMonitor, usageMonitor, phone.getLooper()); 337 } 338 339 @VisibleForTesting SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor, Looper looper)340 public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, 341 SmsUsageMonitor usageMonitor, Looper looper) { 342 super(looper); 343 344 Rlog.d(TAG, "SmsDispatchersController created"); 345 346 mContext = phone.getContext(); 347 mUsageMonitor = usageMonitor; 348 mCi = phone.mCi; 349 mPhone = phone; 350 351 // Create dispatchers, inbound SMS handlers and 352 // broadcast undelivered messages in raw table. 353 mImsSmsDispatcher = new ImsSmsDispatcher(phone, this, ImsManager::getConnector); 354 mCdmaDispatcher = new CdmaSMSDispatcher(phone, this); 355 mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), 356 storageMonitor, phone, looper); 357 mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), 358 storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher, looper); 359 mGsmDispatcher = new GsmSMSDispatcher(phone, this, mGsmInboundSmsHandler); 360 SmsBroadcastUndelivered.initialize(phone.getContext(), 361 mGsmInboundSmsHandler, mCdmaInboundSmsHandler); 362 InboundSmsHandler.registerNewMessageNotificationActionHandler(phone.getContext()); 363 364 mCi.registerForOn(this, EVENT_RADIO_ON, null); 365 mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null); 366 367 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 368 if (userManager.isUserUnlocked()) { 369 if (VDBG) { 370 logd("SmsDispatchersController: user unlocked; registering for service" 371 + "state changed"); 372 } 373 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); 374 resetPartialSegmentWaitTimer(); 375 } else { 376 if (VDBG) { 377 logd("SmsDispatchersController: user locked; waiting for USER_UNLOCKED"); 378 } 379 IntentFilter userFilter = new IntentFilter(); 380 userFilter.addAction(Intent.ACTION_USER_UNLOCKED); 381 mContext.registerReceiver(mBroadcastReceiver, userFilter); 382 } 383 } 384 385 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 386 @Override 387 public void onReceive(final Context context, Intent intent) { 388 Rlog.d(TAG, "Received broadcast " + intent.getAction()); 389 if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 390 sendMessage(obtainMessage(EVENT_USER_UNLOCKED)); 391 } 392 } 393 }; 394 dispose()395 public void dispose() { 396 mCi.unregisterForOn(this); 397 mCi.unregisterForImsNetworkStateChanged(this); 398 mPhone.unregisterForServiceStateChanged(this); 399 mGsmDispatcher.dispose(); 400 mCdmaDispatcher.dispose(); 401 mGsmInboundSmsHandler.dispose(); 402 mCdmaInboundSmsHandler.dispose(); 403 // Cancels the domain selection request if it's still in progress. 404 finishDomainSelection(mDscHolder); 405 finishDomainSelection(mEmergencyDscHolder); 406 } 407 408 /** 409 * Handles events coming from the phone stack. Overridden from handler. 410 * 411 * @param msg the message to handle 412 */ 413 @Override handleMessage(Message msg)414 public void handleMessage(Message msg) { 415 AsyncResult ar; 416 417 switch (msg.what) { 418 case EVENT_RADIO_ON: 419 case EVENT_IMS_STATE_CHANGED: // received unsol 420 mCi.getImsRegistrationState(this.obtainMessage(EVENT_IMS_STATE_DONE)); 421 break; 422 423 case EVENT_IMS_STATE_DONE: 424 ar = (AsyncResult) msg.obj; 425 426 if (ar.exception == null) { 427 updateImsInfo(ar); 428 } else { 429 Rlog.e(TAG, "IMS State query failed with exp " 430 + ar.exception); 431 } 432 break; 433 434 case EVENT_SERVICE_STATE_CHANGED: 435 case EVENT_SMS_HANDLER_EXITING_WAITING_STATE: 436 reevaluateTimerStatus(); 437 break; 438 439 case EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY: 440 handlePartialSegmentTimerExpiry((Long) msg.obj); 441 break; 442 443 case EVENT_USER_UNLOCKED: 444 if (VDBG) { 445 logd("handleMessage: EVENT_USER_UNLOCKED"); 446 } 447 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); 448 resetPartialSegmentWaitTimer(); 449 break; 450 451 default: 452 if (isCdmaMo()) { 453 mCdmaDispatcher.handleMessage(msg); 454 } else { 455 mGsmDispatcher.handleMessage(msg); 456 } 457 } 458 } 459 getSmscAddressFromUSIMWithPhoneIdentity(String callingPkg)460 private String getSmscAddressFromUSIMWithPhoneIdentity(String callingPkg) { 461 final long identity = Binder.clearCallingIdentity(); 462 try { 463 IccSmsInterfaceManager iccSmsIntMgr = mPhone.getIccSmsInterfaceManager(); 464 if (iccSmsIntMgr != null) { 465 return iccSmsIntMgr.getSmscAddressFromIccEf(callingPkg); 466 } else { 467 Rlog.d(TAG, "getSmscAddressFromIccEf iccSmsIntMgr is null"); 468 } 469 } finally { 470 Binder.restoreCallingIdentity(identity); 471 } 472 return null; 473 } 474 reevaluateTimerStatus()475 private void reevaluateTimerStatus() { 476 long currentTime = System.currentTimeMillis(); 477 478 // Remove unhandled timer expiry message. A new message will be posted if needed. 479 removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); 480 // Update timer duration elapsed time (add time since last IN_SERVICE to now). 481 // This is needed for IN_SERVICE as well as OUT_OF_SERVICE because same events can be 482 // received back to back 483 if (mLastInServiceTime != INVALID_TIME) { 484 mCurrentWaitElapsedDuration += (currentTime - mLastInServiceTime); 485 } 486 487 if (VDBG) { 488 logd("reevaluateTimerStatus: currentTime: " + currentTime 489 + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); 490 } 491 492 if (mCurrentWaitElapsedDuration > PARTIAL_SEGMENT_WAIT_DURATION) { 493 // handle this event as timer expiry 494 handlePartialSegmentTimerExpiry(mCurrentWaitStartTime); 495 } else { 496 if (isInService()) { 497 handleInService(currentTime); 498 } else { 499 handleOutOfService(currentTime); 500 } 501 } 502 } 503 handleInService(long currentTime)504 private void handleInService(long currentTime) { 505 if (VDBG) { 506 logd("handleInService: timer expiry in " 507 + (PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration) + "ms"); 508 } 509 510 // initialize mCurrentWaitStartTime if needed 511 if (mCurrentWaitStartTime == INVALID_TIME) mCurrentWaitStartTime = currentTime; 512 513 // Post a message for timer expiry time. mCurrentWaitElapsedDuration is the duration already 514 // elapsed from the timer. 515 sendMessageDelayed( 516 obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), 517 PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration); 518 519 // update mLastInServiceTime as the current time 520 mLastInServiceTime = currentTime; 521 } 522 handleOutOfService(long currentTime)523 private void handleOutOfService(long currentTime) { 524 if (VDBG) { 525 logd("handleOutOfService: currentTime: " + currentTime 526 + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); 527 } 528 529 // mLastInServiceTime is not relevant now since state is OUT_OF_SERVICE; set it to INVALID 530 mLastInServiceTime = INVALID_TIME; 531 } 532 handlePartialSegmentTimerExpiry(long waitTimerStart)533 private void handlePartialSegmentTimerExpiry(long waitTimerStart) { 534 if (mGsmInboundSmsHandler.getCurrentState().getName().equals("WaitingState") 535 || mCdmaInboundSmsHandler.getCurrentState().getName().equals("WaitingState")) { 536 logd("handlePartialSegmentTimerExpiry: ignoring timer expiry as InboundSmsHandler is" 537 + " in WaitingState"); 538 return; 539 } 540 541 if (VDBG) { 542 logd("handlePartialSegmentTimerExpiry: calling scanRawTable()"); 543 } 544 // Timer expired. This indicates that device has been in service for 545 // PARTIAL_SEGMENT_WAIT_DURATION since waitTimerStart. Delete orphaned message segments 546 // older than waitTimerStart. 547 SmsBroadcastUndelivered.scanRawTable(mContext, waitTimerStart); 548 if (VDBG) { 549 logd("handlePartialSegmentTimerExpiry: scanRawTable() done"); 550 } 551 552 resetPartialSegmentWaitTimer(); 553 } 554 resetPartialSegmentWaitTimer()555 private void resetPartialSegmentWaitTimer() { 556 long currentTime = System.currentTimeMillis(); 557 558 removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); 559 if (isInService()) { 560 if (VDBG) { 561 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime 562 + " IN_SERVICE"); 563 } 564 mCurrentWaitStartTime = currentTime; 565 mLastInServiceTime = currentTime; 566 sendMessageDelayed( 567 obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), 568 PARTIAL_SEGMENT_WAIT_DURATION); 569 } else { 570 if (VDBG) { 571 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime 572 + " not IN_SERVICE"); 573 } 574 mCurrentWaitStartTime = INVALID_TIME; 575 mLastInServiceTime = INVALID_TIME; 576 } 577 578 mCurrentWaitElapsedDuration = 0; 579 } 580 isInService()581 private boolean isInService() { 582 ServiceState serviceState = mPhone.getServiceState(); 583 return serviceState != null && serviceState.getState() == ServiceState.STATE_IN_SERVICE; 584 } 585 setImsSmsFormat(int format)586 private void setImsSmsFormat(int format) { 587 switch (format) { 588 case PhoneConstants.PHONE_TYPE_GSM: 589 mImsSmsFormat = SmsConstants.FORMAT_3GPP; 590 break; 591 case PhoneConstants.PHONE_TYPE_CDMA: 592 mImsSmsFormat = SmsConstants.FORMAT_3GPP2; 593 break; 594 default: 595 mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN; 596 break; 597 } 598 } 599 updateImsInfo(AsyncResult ar)600 private void updateImsInfo(AsyncResult ar) { 601 int[] responseArray = (int[]) ar.result; 602 setImsSmsFormat(responseArray[1]); 603 mIms = responseArray[0] == 1 && !SmsConstants.FORMAT_UNKNOWN.equals(mImsSmsFormat); 604 Rlog.d(TAG, "IMS registration state: " + mIms + " format: " + mImsSmsFormat); 605 } 606 607 /** 608 * Inject an SMS PDU into the android platform only if it is class 1. 609 * 610 * @param pdu is the byte array of pdu to be injected into android telephony layer 611 * @param format is the format of SMS pdu (3gpp or 3gpp2) 612 * @param callback if not NULL this callback is triggered when the message is successfully 613 * received by the android telephony layer. This callback is triggered at 614 * the same time an SMS received from radio is responded back. 615 */ 616 @VisibleForTesting injectSmsPdu(byte[] pdu, String format, boolean isOverIms, SmsInjectionCallback callback)617 public void injectSmsPdu(byte[] pdu, String format, boolean isOverIms, 618 SmsInjectionCallback callback) { 619 // TODO We need to decide whether we should allow injecting GSM(3gpp) 620 // SMS pdus when the phone is camping on CDMA(3gpp2) network and vice versa. 621 android.telephony.SmsMessage msg = 622 android.telephony.SmsMessage.createFromPdu(pdu, format); 623 injectSmsPdu(msg, format, callback, false /* ignoreClass */, isOverIms, 0 /* unused */); 624 } 625 626 @VisibleForTesting setImsSmsDispatcher(ImsSmsDispatcher imsSmsDispatcher)627 public void setImsSmsDispatcher(ImsSmsDispatcher imsSmsDispatcher) { 628 mImsSmsDispatcher = imsSmsDispatcher; 629 } 630 631 /** 632 * Inject an SMS PDU into the android platform. 633 * 634 * @param msg is the {@link SmsMessage} to be injected into android telephony layer 635 * @param format is the format of SMS pdu (3gpp or 3gpp2) 636 * @param callback if not NULL this callback is triggered when the message is successfully 637 * received by the android telephony layer. This callback is triggered at 638 * the same time an SMS received from radio is responded back. 639 * @param ignoreClass if set to false, this method will inject class 1 sms only. 640 */ 641 @VisibleForTesting injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, boolean ignoreClass, boolean isOverIms, int token)642 public void injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, 643 boolean ignoreClass, boolean isOverIms, int token) { 644 Rlog.d(TAG, "SmsDispatchersController:injectSmsPdu"); 645 try { 646 if (msg == null) { 647 Rlog.e(TAG, "injectSmsPdu: createFromPdu returned null"); 648 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 649 return; 650 } 651 652 if (!ignoreClass 653 && msg.getMessageClass() != android.telephony.SmsMessage.MessageClass.CLASS_1) { 654 Rlog.e(TAG, "injectSmsPdu: not class 1"); 655 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 656 return; 657 } 658 659 AsyncResult ar = new AsyncResult(callback, msg, null); 660 661 if (format.equals(SmsConstants.FORMAT_3GPP)) { 662 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg 663 + ", format=" + format + "to mGsmInboundSmsHandler"); 664 mGsmInboundSmsHandler.sendMessage( 665 InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, token, ar); 666 } else if (format.equals(SmsConstants.FORMAT_3GPP2)) { 667 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg 668 + ", format=" + format + "to mCdmaInboundSmsHandler"); 669 mCdmaInboundSmsHandler.sendMessage( 670 InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, 0, ar); 671 } else { 672 // Invalid pdu format. 673 Rlog.e(TAG, "Invalid pdu format: " + format); 674 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 675 } 676 } catch (Exception e) { 677 Rlog.e(TAG, "injectSmsPdu failed: ", e); 678 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 679 } 680 } 681 682 /** 683 * sets ImsManager object. 684 * 685 * @param imsManager holds a valid object or a null for setting 686 */ setImsManager(ImsManager imsManager)687 public boolean setImsManager(ImsManager imsManager) { 688 if (mGsmInboundSmsHandler != null) { 689 mGsmInboundSmsHandler.setImsManager(imsManager); 690 return true; 691 } 692 return false; 693 } 694 695 /** 696 * Retry the message along to the radio. 697 * 698 * @param tracker holds the SMS message to send 699 */ sendRetrySms(SMSDispatcher.SmsTracker tracker)700 public void sendRetrySms(SMSDispatcher.SmsTracker tracker) { 701 boolean retryUsingImsService = false; 702 703 if (!tracker.mUsesImsServiceForIms) { 704 if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { 705 DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); 706 707 // If the DomainSelectionConnection is not available, 708 // fallback to the legacy implementation. 709 if (holder != null && holder.getConnection() != null) { 710 sendSmsUsingDomainSelection(holder, 711 new PendingRequest(PendingRequest.TYPE_RETRY_SMS, tracker, 712 null, null, null, null, null, false, null, 0, null, null, false, 713 0, false, 0, 0L, false), 714 "sendRetrySms"); 715 return; 716 } 717 } 718 719 if (mImsSmsDispatcher.isAvailable()) { 720 // If this tracker has not been handled by ImsSmsDispatcher yet and IMS Service is 721 // available now, retry this failed tracker using IMS Service. 722 retryUsingImsService = true; 723 } 724 } 725 726 sendRetrySms(tracker, retryUsingImsService); 727 } 728 729 /** 730 * Retry the message along to the radio. 731 * 732 * @param tracker holds the SMS message to send 733 * @param retryUsingImsService a flag to indicate whether the retry SMS can use the ImsService 734 */ sendRetrySms(SMSDispatcher.SmsTracker tracker, boolean retryUsingImsService)735 public void sendRetrySms(SMSDispatcher.SmsTracker tracker, boolean retryUsingImsService) { 736 String oldFormat = tracker.mFormat; 737 // If retryUsingImsService is true, newFormat will be IMS SMS format. Otherwise, newFormat 738 // will be based on voice technology. 739 String newFormat = 740 retryUsingImsService 741 ? mImsSmsDispatcher.getFormat() 742 : (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()) 743 ? mCdmaDispatcher.getFormat() 744 : mGsmDispatcher.getFormat(); 745 746 Rlog.d(TAG, "old format(" + oldFormat + ") ==> new format (" + newFormat + ")"); 747 if (!oldFormat.equals(newFormat)) { 748 // format didn't match, need to re-encode. 749 HashMap map = tracker.getData(); 750 751 // to re-encode, fields needed are: scAddr, destAddr and text if originally sent as 752 // sendText or data and destPort if originally sent as sendData. 753 if (!(map.containsKey("scAddr") && map.containsKey("destAddr") 754 && (map.containsKey("text") 755 || (map.containsKey("data") && map.containsKey("destPort"))))) { 756 // should never come here... 757 Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!"); 758 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 759 return; 760 } 761 String scAddr = (String) map.get("scAddr"); 762 String destAddr = (String) map.get("destAddr"); 763 if (destAddr == null) { 764 Rlog.e(TAG, "sendRetrySms failed due to null destAddr"); 765 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 766 return; 767 } 768 769 SmsMessageBase.SubmitPduBase pdu = null; 770 // figure out from tracker if this was sendText/Data 771 if (map.containsKey("text")) { 772 String text = (String) map.get("text"); 773 Rlog.d(TAG, "sms failed was text with length: " 774 + (text == null ? null : text.length())); 775 776 if (isCdmaFormat(newFormat)) { 777 pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( 778 scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null); 779 } else { 780 pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( 781 scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null, 782 0, 0, 0, -1, tracker.mMessageRef); 783 } 784 } else if (map.containsKey("data")) { 785 byte[] data = (byte[]) map.get("data"); 786 Integer destPort = (Integer) map.get("destPort"); 787 Rlog.d(TAG, "sms failed was data with length: " 788 + (data == null ? null : data.length)); 789 790 if (isCdmaFormat(newFormat)) { 791 pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( 792 scAddr, destAddr, destPort.intValue(), data, 793 (tracker.mDeliveryIntent != null)); 794 } else { 795 pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( 796 scAddr, destAddr, destPort.intValue(), data, 797 (tracker.mDeliveryIntent != null), tracker.mMessageRef); 798 } 799 } 800 801 if (pdu == null) { 802 Rlog.e(TAG, String.format("sendRetrySms failed to encode message." 803 + "scAddr: %s, " 804 + "destPort: %s", scAddr, map.get("destPort"))); 805 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 806 return; 807 } 808 // replace old smsc and pdu with newly encoded ones 809 map.put("smsc", pdu.encodedScAddress); 810 map.put("pdu", pdu.encodedMessage); 811 tracker.mFormat = newFormat; 812 } 813 814 SMSDispatcher dispatcher = 815 retryUsingImsService 816 ? mImsSmsDispatcher 817 : (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher; 818 819 dispatcher.sendSms(tracker); 820 } 821 822 /** 823 * Memory Available Event 824 * @param result callback message 825 */ reportSmsMemoryStatus(Message result)826 public void reportSmsMemoryStatus(Message result) { 827 Rlog.d(TAG, "reportSmsMemoryStatus: "); 828 try { 829 mImsSmsDispatcher.onMemoryAvailable(); 830 AsyncResult.forMessage(result, null, null); 831 result.sendToTarget(); 832 } catch (Exception e) { 833 Rlog.e(TAG, "reportSmsMemoryStatus Failed ", e); 834 AsyncResult.forMessage(result, null, e); 835 result.sendToTarget(); 836 } 837 } 838 839 /** 840 * SMS over IMS is supported if IMS is registered and SMS is supported on IMS. 841 * 842 * @return true if SMS over IMS is supported via an IMS Service or mIms is true for the older 843 * implementation. Otherwise, false. 844 */ isIms()845 public boolean isIms() { 846 return mImsSmsDispatcher.isAvailable() ? true : mIms; 847 } 848 849 /** 850 * Gets SMS format supported on IMS. 851 * 852 * @return the SMS format from an IMS Service if available. Otherwise, mImsSmsFormat for the 853 * older implementation. 854 */ getImsSmsFormat()855 public String getImsSmsFormat() { 856 return mImsSmsDispatcher.isAvailable() ? mImsSmsDispatcher.getFormat() : mImsSmsFormat; 857 } 858 859 /** 860 * Determines whether or not to use CDMA format for MO SMS. 861 * If SMS over IMS is supported, then format is based on IMS SMS format, 862 * otherwise format is based on current phone type. 863 * 864 * @return true if Cdma format should be used for MO SMS, false otherwise. 865 */ isCdmaMo()866 protected boolean isCdmaMo() { 867 if (!isIms()) { 868 // IMS is not registered, use Voice technology to determine SMS format. 869 return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()); 870 } 871 // IMS is registered with SMS support 872 return isCdmaFormat(getImsSmsFormat()); 873 } 874 875 /** 876 * Determines whether or not format given is CDMA format. 877 * 878 * @param format 879 * @return true if format given is CDMA format, false otherwise. 880 */ isCdmaFormat(String format)881 public boolean isCdmaFormat(String format) { 882 return (mCdmaDispatcher.getFormat().equals(format)); 883 } 884 885 /** Sets a proxy interface for accessing the methods of {@link DomainSelectionResolver}. */ 886 @VisibleForTesting setDomainSelectionResolverProxy(@onNull DomainSelectionResolverProxy proxy)887 public void setDomainSelectionResolverProxy(@NonNull DomainSelectionResolverProxy proxy) { 888 mDomainSelectionResolverProxy = proxy; 889 } 890 891 /** 892 * Determines whether or not to use CDMA format for MO SMS when the domain selection uses. 893 * If the domain is {@link NetworkRegistrationInfo#DOMAIN_PS}, then format is based on 894 * IMS SMS format, otherwise format is based on current phone type. 895 * 896 * @return {@code true} if CDMA format should be used for MO SMS, {@code false} otherwise. 897 */ isCdmaMo(@etworkRegistrationInfo.Domain int domain)898 private boolean isCdmaMo(@NetworkRegistrationInfo.Domain int domain) { 899 if (domain != NetworkRegistrationInfo.DOMAIN_PS) { 900 // IMS is not registered, use voice technology to determine SMS format. 901 return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()); 902 } 903 // IMS is registered with SMS support 904 return isCdmaFormat(mImsSmsDispatcher.getFormat()); 905 } 906 907 /** 908 * Returns a {@link DomainSelectionConnectionHolder} according to the flag specified. 909 * 910 * @param emergency The flag to indicate that the domain selection is for an emergency SMS. 911 * @return A {@link DomainSelectionConnectionHolder} instance or null. 912 */ 913 @VisibleForTesting 914 @Nullable getDomainSelectionConnectionHolder( boolean emergency)915 protected DomainSelectionConnectionHolder getDomainSelectionConnectionHolder( 916 boolean emergency) { 917 return emergency ? mEmergencyDscHolder : mDscHolder; 918 } 919 920 /** 921 * Returns a {@link DomainSelectionConnectionHolder} if the domain selection supports, 922 * return null otherwise. 923 * 924 * @param emergency The flag to indicate that the domain selection is for an emergency SMS. 925 * @return A {@link DomainSelectionConnectionHolder} that grabs the 926 * {@link DomainSelectionConnection} and its related information to use the domain 927 * selection architecture. 928 */ getDomainSelectionConnection(boolean emergency)929 private DomainSelectionConnectionHolder getDomainSelectionConnection(boolean emergency) { 930 DomainSelectionConnectionHolder holder = getDomainSelectionConnectionHolder(emergency); 931 DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null; 932 boolean created = false; 933 934 if (connection == null) { 935 connection = mDomainSelectionResolverProxy.getDomainSelectionConnection( 936 mPhone, DomainSelectionService.SELECTOR_TYPE_SMS, emergency); 937 938 if (connection == null) { 939 // Domain selection architecture is not supported. 940 // Use the legacy architecture. 941 return null; 942 } 943 944 created = true; 945 } 946 947 if (holder == null) { 948 holder = new DomainSelectionConnectionHolder(emergency); 949 950 if (emergency) { 951 mEmergencyDscHolder = holder; 952 } else { 953 mDscHolder = holder; 954 } 955 } 956 957 holder.setConnection(connection); 958 959 return holder; 960 } 961 962 /** 963 * Requests the domain selection for MO SMS. 964 * 965 * @param holder The {@link DomainSelectionConnectionHolder} that contains the 966 * {@link DomainSelectionConnection} and its related information. 967 */ requestDomainSelection(@onNull DomainSelectionConnectionHolder holder)968 private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder) { 969 DomainSelectionService.SelectionAttributes attr = 970 new DomainSelectionService.SelectionAttributes.Builder(mPhone.getPhoneId(), 971 mPhone.getSubId(), DomainSelectionService.SELECTOR_TYPE_SMS) 972 .setEmergency(holder.isEmergency()) 973 .build(); 974 975 if (holder.isEmergency()) { 976 EmergencySmsDomainSelectionConnection emergencyConnection = 977 (EmergencySmsDomainSelectionConnection) holder.getConnection(); 978 CompletableFuture<Integer> future = 979 emergencyConnection.requestDomainSelection(attr, holder); 980 future.thenAcceptAsync((domain) -> { 981 if (VDBG) { 982 logd("requestDomainSelection(emergency): domain=" 983 + DomainSelectionService.getDomainName(domain)); 984 } 985 sendAllPendingRequests(holder, domain); 986 finishDomainSelection(holder); 987 }, this::post); 988 } else { 989 SmsDomainSelectionConnection connection = 990 (SmsDomainSelectionConnection) holder.getConnection(); 991 CompletableFuture<Integer> future = connection.requestDomainSelection(attr, holder); 992 future.thenAcceptAsync((domain) -> { 993 if (VDBG) { 994 logd("requestDomainSelection: domain=" 995 + DomainSelectionService.getDomainName(domain)); 996 } 997 sendAllPendingRequests(holder, domain); 998 finishDomainSelection(holder); 999 }, this::post); 1000 } 1001 } 1002 1003 /** 1004 * Sends a SMS after selecting the domain via the domain selection service. 1005 * 1006 * @param holder The {@link DomainSelectionConnectionHolder} that contains the 1007 * {@link DomainSelectionConnection} and its related information. 1008 * @param request The {@link PendingRequest} that stores the SMS request 1009 * (data, text, multipart text) to be sent. 1010 * @param logTag The log tag to display which method called this method. 1011 */ sendSmsUsingDomainSelection(@onNull DomainSelectionConnectionHolder holder, @NonNull PendingRequest request, @NonNull String logTag)1012 private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder, 1013 @NonNull PendingRequest request, @NonNull String logTag) { 1014 boolean isDomainSelectionRequested = holder.isDomainSelectionRequested(); 1015 // The domain selection is in progress so waits for the result of 1016 // the domain selection by adding this request to the pending list. 1017 holder.addRequest(request); 1018 1019 if (!isDomainSelectionRequested) { 1020 if (VDBG) { 1021 logd("requestDomainSelection: " + logTag); 1022 } 1023 requestDomainSelection(holder); 1024 } 1025 } 1026 1027 /** 1028 * Finishes the domain selection for MO SMS. 1029 * 1030 * @param holder The {@link DomainSelectionConnectionHolder} object that is being finished. 1031 */ finishDomainSelection(DomainSelectionConnectionHolder holder)1032 private void finishDomainSelection(DomainSelectionConnectionHolder holder) { 1033 DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null; 1034 1035 if (connection != null) { 1036 // After this method is called, the domain selection service will clean up 1037 // its resources and finish the procedure that are related to the current domain 1038 // selection request. 1039 connection.finishSelection(); 1040 } 1041 1042 if (holder != null) { 1043 final List<PendingRequest> pendingRequests = holder.getPendingRequests(); 1044 1045 logd("finishDomainSelection: pendingRequests=" + pendingRequests.size()); 1046 1047 for (PendingRequest r : pendingRequests) { 1048 triggerSentIntentForFailure(r.sentIntents); 1049 } 1050 1051 holder.clearAllRequests(); 1052 holder.setConnection(null); 1053 } 1054 } 1055 1056 /** 1057 * Notifies the application that MO SMS is not sent by the error of domain selection. 1058 * 1059 * @param holder The {@link DomainSelectionConnectionHolder} object that is being terminated. 1060 */ notifyDomainSelectionTerminated(@onNull DomainSelectionConnectionHolder holder)1061 private void notifyDomainSelectionTerminated(@NonNull DomainSelectionConnectionHolder holder) { 1062 final List<PendingRequest> pendingRequests = holder.getPendingRequests(); 1063 1064 logd("notifyDomainSelectionTerminated: pendingRequests=" + pendingRequests.size()); 1065 1066 for (PendingRequest r : pendingRequests) { 1067 triggerSentIntentForFailure(r.sentIntents); 1068 } 1069 1070 holder.setConnection(null); 1071 holder.clearAllRequests(); 1072 } 1073 1074 /** 1075 * Sends all pending requests for MO SMS. 1076 * 1077 * @param holder The {@link DomainSelectionConnectionHolder} object that all the pending 1078 * requests are handled. 1079 * @param domain The domain where the SMS is being sent, which can be one of the following: 1080 * - {@link NetworkRegistrationInfo#DOMAIN_PS} 1081 * - {@link NetworkRegistrationInfo#DOMAIN_CS} 1082 */ sendAllPendingRequests(@onNull DomainSelectionConnectionHolder holder, @NetworkRegistrationInfo.Domain int domain)1083 private void sendAllPendingRequests(@NonNull DomainSelectionConnectionHolder holder, 1084 @NetworkRegistrationInfo.Domain int domain) { 1085 final List<PendingRequest> pendingRequests = holder.getPendingRequests(); 1086 1087 if (VDBG) { 1088 logd("sendAllPendingRequests: domain=" + DomainSelectionService.getDomainName(domain) 1089 + ", size=" + pendingRequests.size()); 1090 } 1091 1092 for (PendingRequest r : pendingRequests) { 1093 switch (r.type) { 1094 case PendingRequest.TYPE_DATA: 1095 sendData(domain, r); 1096 break; 1097 case PendingRequest.TYPE_TEXT: 1098 sendText(domain, r); 1099 break; 1100 case PendingRequest.TYPE_MULTIPART_TEXT: 1101 sendMultipartText(domain, r); 1102 break; 1103 case PendingRequest.TYPE_RETRY_SMS: 1104 sendRetrySms(r.tracker, (domain == NetworkRegistrationInfo.DOMAIN_PS)); 1105 break; 1106 default: 1107 // Not reachable. 1108 break; 1109 } 1110 } 1111 1112 holder.clearAllRequests(); 1113 } 1114 1115 /** 1116 * Sends a data based SMS to a specific application port. 1117 * 1118 * @param domain The domain where the SMS is being sent, which can be one of the following: 1119 * - {@link NetworkRegistrationInfo#DOMAIN_PS} 1120 * - {@link NetworkRegistrationInfo#DOMAIN_CS} 1121 * @param request The pending request for MO SMS. 1122 */ sendData(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1123 private void sendData(@NetworkRegistrationInfo.Domain int domain, 1124 @NonNull PendingRequest request) { 1125 if (domain == NetworkRegistrationInfo.DOMAIN_PS) { 1126 mImsSmsDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr, 1127 request.destPort, request.data, request.sentIntents.get(0), 1128 request.deliveryIntents.get(0), request.isForVvm); 1129 } else if (isCdmaMo(domain)) { 1130 mCdmaDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr, 1131 request.destPort, request.data, request.sentIntents.get(0), 1132 request.deliveryIntents.get(0), request.isForVvm); 1133 } else { 1134 mGsmDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr, 1135 request.destPort, request.data, request.sentIntents.get(0), 1136 request.deliveryIntents.get(0), request.isForVvm); 1137 } 1138 } 1139 1140 /** 1141 * Sends a text based SMS. 1142 * 1143 * @param domain The domain where the SMS is being sent, which can be one of the following: 1144 * - {@link NetworkRegistrationInfo#DOMAIN_PS} 1145 * - {@link NetworkRegistrationInfo#DOMAIN_CS} 1146 * @param request The pending request for MO SMS. 1147 */ sendText(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1148 private void sendText(@NetworkRegistrationInfo.Domain int domain, 1149 @NonNull PendingRequest request) { 1150 if (domain == NetworkRegistrationInfo.DOMAIN_PS) { 1151 mImsSmsDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1152 request.sentIntents.get(0), request.deliveryIntents.get(0), 1153 request.messageUri, request.callingPackage, request.persistMessage, 1154 request.priority, false /*request.expectMore*/, request.validityPeriod, 1155 request.isForVvm, request.messageId, request.skipShortCodeCheck); 1156 } else { 1157 if (isCdmaMo(domain)) { 1158 mCdmaDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1159 request.sentIntents.get(0), request.deliveryIntents.get(0), 1160 request.messageUri, request.callingPackage, request.persistMessage, 1161 request.priority, request.expectMore, request.validityPeriod, 1162 request.isForVvm, request.messageId, request.skipShortCodeCheck); 1163 } else { 1164 mGsmDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1165 request.sentIntents.get(0), request.deliveryIntents.get(0), 1166 request.messageUri, request.callingPackage, request.persistMessage, 1167 request.priority, request.expectMore, request.validityPeriod, 1168 request.isForVvm, request.messageId, request.skipShortCodeCheck); 1169 } 1170 } 1171 } 1172 1173 /** 1174 * Sends a multi-part text based SMS. 1175 * 1176 * @param domain The domain where the SMS is being sent, which can be one of the following: 1177 * - {@link NetworkRegistrationInfo#DOMAIN_PS} 1178 * - {@link NetworkRegistrationInfo#DOMAIN_CS} 1179 * @param request The pending request for MO SMS. 1180 */ sendMultipartText(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1181 private void sendMultipartText(@NetworkRegistrationInfo.Domain int domain, 1182 @NonNull PendingRequest request) { 1183 if (domain == NetworkRegistrationInfo.DOMAIN_PS) { 1184 mImsSmsDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 1185 request.sentIntents, request.deliveryIntents, request.messageUri, 1186 request.callingPackage, request.persistMessage, request.priority, 1187 false /*request.expectMore*/, request.validityPeriod, request.messageId); 1188 } else { 1189 if (isCdmaMo(domain)) { 1190 mCdmaDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 1191 request.sentIntents, request.deliveryIntents, request.messageUri, 1192 request.callingPackage, request.persistMessage, request.priority, 1193 request.expectMore, request.validityPeriod, request.messageId); 1194 } else { 1195 mGsmDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 1196 request.sentIntents, request.deliveryIntents, request.messageUri, 1197 request.callingPackage, request.persistMessage, request.priority, 1198 request.expectMore, request.validityPeriod, request.messageId); 1199 } 1200 } 1201 } 1202 triggerSentIntentForFailure(@onNull PendingIntent sentIntent)1203 private void triggerSentIntentForFailure(@NonNull PendingIntent sentIntent) { 1204 try { 1205 sentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); 1206 } catch (CanceledException e) { 1207 logd("Intent has been canceled!"); 1208 } 1209 } 1210 triggerSentIntentForFailure(@onNull List<PendingIntent> sentIntents)1211 private void triggerSentIntentForFailure(@NonNull List<PendingIntent> sentIntents) { 1212 for (PendingIntent sentIntent : sentIntents) { 1213 triggerSentIntentForFailure(sentIntent); 1214 } 1215 } 1216 1217 /** 1218 * Creates an ArrayList object from any object. 1219 */ asArrayList(T object)1220 private static <T> ArrayList<T> asArrayList(T object) { 1221 ArrayList<T> list = new ArrayList<>(); 1222 list.add(object); 1223 return list; 1224 } 1225 1226 /** 1227 * Send a data based SMS to a specific application port. 1228 * 1229 * @param callingPackage the package name of the calling app 1230 * @param destAddr the address to send the message to 1231 * @param scAddr is the service center address or null to use 1232 * the current default SMSC 1233 * @param destPort the port to deliver the message to 1234 * @param data the body of the message to send 1235 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1236 * broadcast when the message is successfully sent, or failed. 1237 * The result code will be <code>Activity.RESULT_OK<code> for success, 1238 * or one of these errors:<br> 1239 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 1240 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 1241 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 1242 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 1243 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 1244 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 1245 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 1246 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 1247 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 1248 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 1249 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 1250 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 1251 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 1252 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 1253 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 1254 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 1255 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 1256 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 1257 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 1258 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 1259 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 1260 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 1261 * <code>SmsManager.RESULT_CANCELLED</code><br> 1262 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 1263 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 1264 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 1265 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 1266 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 1267 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 1268 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 1269 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 1270 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 1271 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 1272 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 1273 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 1274 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 1275 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 1276 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 1277 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 1278 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 1279 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 1280 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 1281 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 1282 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 1283 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 1284 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 1285 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 1286 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 1287 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 1288 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 1289 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 1290 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 1291 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 1292 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 1293 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 1294 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 1295 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 1296 * the sentIntent may include the extra "errorCode" containing a radio technology specific 1297 * value, generally only useful for troubleshooting.<br> 1298 * The per-application based SMS control checks sentIntent. If sentIntent 1299 * is NULL the caller will be checked against all unknown applications, 1300 * which cause smaller number of SMS to be sent in checking period. 1301 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1302 * broadcast when the message is delivered to the recipient. The 1303 * raw pdu of the status report is in the extended data ("pdu"). 1304 */ sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)1305 protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort, 1306 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) { 1307 if (TextUtils.isEmpty(scAddr)) { 1308 scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPackage); 1309 } 1310 1311 if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { 1312 DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); 1313 1314 // If the DomainSelectionConnection is not available, 1315 // fallback to the legacy implementation. 1316 if (holder != null && holder.getConnection() != null) { 1317 sendSmsUsingDomainSelection(holder, 1318 new PendingRequest(PendingRequest.TYPE_DATA, null, callingPackage, 1319 destAddr, scAddr, asArrayList(sentIntent), 1320 asArrayList(deliveryIntent), isForVvm, data, destPort, null, null, 1321 false, 0, false, 0, 0L, false), 1322 "sendData"); 1323 return; 1324 } 1325 } 1326 1327 if (mImsSmsDispatcher.isAvailable()) { 1328 mImsSmsDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent, 1329 deliveryIntent, isForVvm); 1330 } else if (isCdmaMo()) { 1331 mCdmaDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent, 1332 deliveryIntent, isForVvm); 1333 } else { 1334 mGsmDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent, 1335 deliveryIntent, isForVvm); 1336 } 1337 } 1338 1339 /** 1340 * Send a text based SMS. 1341 * 1342 * @param destAddr the address to send the message to 1343 * @param scAddr is the service center address or null to use 1344 * the current default SMSC 1345 * @param text the body of the message to send 1346 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1347 * broadcast when the message is successfully sent, or failed. 1348 * The result code will be <code>Activity.RESULT_OK<code> for success, 1349 * or one of these errors:<br> 1350 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 1351 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 1352 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 1353 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 1354 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 1355 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 1356 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 1357 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 1358 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 1359 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 1360 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 1361 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 1362 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 1363 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 1364 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 1365 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 1366 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 1367 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 1368 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 1369 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 1370 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 1371 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 1372 * <code>SmsManager.RESULT_CANCELLED</code><br> 1373 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 1374 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 1375 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 1376 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 1377 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 1378 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 1379 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 1380 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 1381 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 1382 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 1383 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 1384 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 1385 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 1386 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 1387 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 1388 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 1389 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 1390 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 1391 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 1392 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 1393 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 1394 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 1395 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 1396 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 1397 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 1398 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 1399 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 1400 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 1401 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 1402 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 1403 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 1404 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 1405 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 1406 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 1407 * the sentIntent may include the extra "errorCode" containing a radio technology specific 1408 * value, generally only useful for troubleshooting.<br> 1409 * The per-application based SMS control checks sentIntent. If sentIntent 1410 * is NULL the caller will be checked against all unknown applications, 1411 * which cause smaller number of SMS to be sent in checking period. 1412 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1413 * broadcast when the message is delivered to the recipient. The 1414 * @param messageUri optional URI of the message if it is already stored in the system 1415 * @param callingPkg the calling package name 1416 * @param persistMessage whether to save the sent message into SMS DB for a 1417 * non-default SMS app. 1418 * @param priority Priority level of the message 1419 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 1420 * --------------------------------- 1421 * PRIORITY | Level of Priority 1422 * --------------------------------- 1423 * '00' | Normal 1424 * '01' | Interactive 1425 * '10' | Urgent 1426 * '11' | Emergency 1427 * ---------------------------------- 1428 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 1429 * @param expectMore is a boolean to indicate the sending messages through same link or not. 1430 * @param validityPeriod Validity Period of the message in mins. 1431 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 1432 * Validity Period(Minimum) -> 5 mins 1433 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 1434 * Any Other values included Negative considered as Invalid Validity Period of the message. 1435 */ sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId)1436 public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, 1437 PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, 1438 int priority, boolean expectMore, int validityPeriod, boolean isForVvm, 1439 long messageId) { 1440 sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, 1441 persistMessage, priority, expectMore, validityPeriod, isForVvm, messageId, false); 1442 } 1443 1444 /** 1445 * Send a text based SMS. 1446 * 1447 * @param destAddr the address to send the message to 1448 * @param scAddr is the service center address or null to use 1449 * the current default SMSC 1450 * @param text the body of the message to send 1451 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1452 * broadcast when the message is successfully sent, or failed. 1453 * The result code will be <code>Activity.RESULT_OK<code> for success, 1454 * or one of these errors:<br> 1455 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 1456 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 1457 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 1458 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 1459 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 1460 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 1461 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 1462 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 1463 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 1464 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 1465 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 1466 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 1467 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 1468 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 1469 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 1470 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 1471 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 1472 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 1473 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 1474 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 1475 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 1476 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 1477 * <code>SmsManager.RESULT_CANCELLED</code><br> 1478 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 1479 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 1480 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 1481 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 1482 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 1483 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 1484 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 1485 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 1486 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 1487 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 1488 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 1489 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 1490 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 1491 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 1492 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 1493 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 1494 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 1495 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 1496 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 1497 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 1498 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 1499 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 1500 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 1501 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 1502 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 1503 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 1504 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 1505 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 1506 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 1507 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 1508 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 1509 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 1510 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 1511 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 1512 * the sentIntent may include the extra "errorCode" containing a radio technology specific 1513 * value, generally only useful for troubleshooting.<br> 1514 * The per-application based SMS control checks sentIntent. If sentIntent 1515 * is NULL the caller will be checked against all unknown applications, 1516 * which cause smaller number of SMS to be sent in checking period. 1517 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1518 * broadcast when the message is delivered to the recipient. The 1519 * @param messageUri optional URI of the message if it is already stored in the system 1520 * @param callingPkg the calling package name 1521 * @param persistMessage whether to save the sent message into SMS DB for a 1522 * non-default SMS app. 1523 * @param priority Priority level of the message 1524 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 1525 * --------------------------------- 1526 * PRIORITY | Level of Priority 1527 * --------------------------------- 1528 * '00' | Normal 1529 * '01' | Interactive 1530 * '10' | Urgent 1531 * '11' | Emergency 1532 * ---------------------------------- 1533 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 1534 * @param expectMore is a boolean to indicate the sending messages through same link or not. 1535 * @param validityPeriod Validity Period of the message in mins. 1536 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 1537 * Validity Period(Minimum) -> 5 mins 1538 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 1539 * Any Other values included Negative considered as Invalid Validity Period of the message. 1540 * @param skipShortCodeCheck Skip check for short code type destination address. 1541 */ sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId, boolean skipShortCodeCheck)1542 public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, 1543 PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, 1544 int priority, boolean expectMore, int validityPeriod, boolean isForVvm, 1545 long messageId, boolean skipShortCodeCheck) { 1546 if (TextUtils.isEmpty(scAddr)) { 1547 scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg); 1548 } 1549 1550 if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { 1551 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 1552 boolean isEmergency = tm.isEmergencyNumber(destAddr); 1553 DomainSelectionConnectionHolder holder = getDomainSelectionConnection(isEmergency); 1554 1555 // If the DomainSelectionConnection is not available, 1556 // fallback to the legacy implementation. 1557 if (holder != null && holder.getConnection() != null) { 1558 sendSmsUsingDomainSelection(holder, 1559 new PendingRequest(PendingRequest.TYPE_TEXT, null, callingPkg, 1560 destAddr, scAddr, asArrayList(sentIntent), 1561 asArrayList(deliveryIntent), isForVvm, null, 0, asArrayList(text), 1562 messageUri, persistMessage, priority, expectMore, validityPeriod, 1563 messageId, skipShortCodeCheck), 1564 "sendText"); 1565 return; 1566 } 1567 } 1568 1569 if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport(destAddr)) { 1570 mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, 1571 messageUri, callingPkg, persistMessage, priority, false /*expectMore*/, 1572 validityPeriod, isForVvm, messageId, skipShortCodeCheck); 1573 } else { 1574 if (isCdmaMo()) { 1575 mCdmaDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, 1576 messageUri, callingPkg, persistMessage, priority, expectMore, 1577 validityPeriod, isForVvm, messageId, skipShortCodeCheck); 1578 } else { 1579 mGsmDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, 1580 messageUri, callingPkg, persistMessage, priority, expectMore, 1581 validityPeriod, isForVvm, messageId, skipShortCodeCheck); 1582 } 1583 } 1584 } 1585 1586 /** 1587 * Send a multi-part text based SMS. 1588 * 1589 * @param destAddr the address to send the message to 1590 * @param scAddr is the service center address or null to use 1591 * the current default SMSC 1592 * @param parts an <code>ArrayList</code> of strings that, in order, 1593 * comprise the original message 1594 * @param sentIntents if not null, an <code>ArrayList</code> of 1595 * <code>PendingIntent</code>s (one for each message part) that is 1596 * broadcast when the corresponding message part has been sent. 1597 * The result code will be <code>Activity.RESULT_OK<code> for success, 1598 * or one of these errors:<br> 1599 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 1600 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 1601 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 1602 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 1603 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 1604 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 1605 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 1606 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 1607 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 1608 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 1609 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 1610 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 1611 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 1612 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 1613 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 1614 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 1615 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 1616 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 1617 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 1618 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 1619 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 1620 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 1621 * <code>SmsManager.RESULT_CANCELLED</code><br> 1622 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 1623 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 1624 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 1625 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 1626 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 1627 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 1628 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 1629 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 1630 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 1631 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 1632 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 1633 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 1634 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 1635 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 1636 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 1637 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 1638 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 1639 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 1640 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 1641 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 1642 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 1643 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 1644 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 1645 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 1646 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 1647 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 1648 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 1649 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 1650 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 1651 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 1652 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 1653 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 1654 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 1655 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 1656 * the sentIntent may include the extra "errorCode" containing a radio technology specific 1657 * value, generally only useful for troubleshooting.<br> 1658 * The per-application based SMS control checks sentIntent. If sentIntent 1659 * is NULL the caller will be checked against all unknown applications, 1660 * which cause smaller number of SMS to be sent in checking period. 1661 * @param deliveryIntents if not null, an <code>ArrayList</code> of 1662 * <code>PendingIntent</code>s (one for each message part) that is 1663 * broadcast when the corresponding message part has been delivered 1664 * to the recipient. The raw pdu of the status report is in the 1665 * @param messageUri optional URI of the message if it is already stored in the system 1666 * @param callingPkg the calling package name 1667 * @param persistMessage whether to save the sent message into SMS DB for a 1668 * non-default SMS app. 1669 * @param priority Priority level of the message 1670 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 1671 * --------------------------------- 1672 * PRIORITY | Level of Priority 1673 * --------------------------------- 1674 * '00' | Normal 1675 * '01' | Interactive 1676 * '10' | Urgent 1677 * '11' | Emergency 1678 * ---------------------------------- 1679 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 1680 * @param expectMore is a boolean to indicate the sending messages through same link or not. 1681 * @param validityPeriod Validity Period of the message in mins. 1682 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 1683 * Validity Period(Minimum) -> 5 mins 1684 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 1685 * Any Other values included Negative considered as Invalid Validity Period of the message. 1686 * @param messageId An id that uniquely identifies the message requested to be sent. 1687 * Used for logging and diagnostics purposes. The id may be 0. 1688 * 1689 */ sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId)1690 protected void sendMultipartText(String destAddr, String scAddr, 1691 ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, 1692 ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, 1693 boolean persistMessage, int priority, boolean expectMore, int validityPeriod, 1694 long messageId) { 1695 if (TextUtils.isEmpty(scAddr)) { 1696 scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg); 1697 } 1698 1699 if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { 1700 DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); 1701 1702 // If the DomainSelectionConnection is not available, 1703 // fallback to the legacy implementation. 1704 if (holder != null && holder.getConnection() != null) { 1705 sendSmsUsingDomainSelection(holder, 1706 new PendingRequest(PendingRequest.TYPE_MULTIPART_TEXT, null, 1707 callingPkg, destAddr, scAddr, sentIntents, deliveryIntents, false, 1708 null, 0, parts, messageUri, persistMessage, priority, expectMore, 1709 validityPeriod, messageId, false), 1710 "sendMultipartText"); 1711 return; 1712 } 1713 } 1714 1715 if (mImsSmsDispatcher.isAvailable()) { 1716 mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, 1717 deliveryIntents, messageUri, callingPkg, persistMessage, priority, 1718 false /*expectMore*/, validityPeriod, messageId); 1719 } else { 1720 if (isCdmaMo()) { 1721 mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, 1722 deliveryIntents, messageUri, callingPkg, persistMessage, priority, 1723 expectMore, validityPeriod, messageId); 1724 } else { 1725 mGsmDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, 1726 deliveryIntents, messageUri, callingPkg, persistMessage, priority, 1727 expectMore, validityPeriod, messageId); 1728 } 1729 } 1730 } 1731 1732 /** 1733 * Returns the premium SMS permission for the specified package. If the package has never 1734 * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN} 1735 * will be returned. 1736 * @param packageName the name of the package to query permission 1737 * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN}, 1738 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}, 1739 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 1740 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 1741 */ getPremiumSmsPermission(String packageName)1742 public int getPremiumSmsPermission(String packageName) { 1743 return mUsageMonitor.getPremiumSmsPermission(packageName); 1744 } 1745 1746 /** 1747 * Sets the premium SMS permission for the specified package and save the value asynchronously 1748 * to persistent storage. 1749 * @param packageName the name of the package to set permission 1750 * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}, 1751 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 1752 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 1753 */ setPremiumSmsPermission(String packageName, int permission)1754 public void setPremiumSmsPermission(String packageName, int permission) { 1755 mUsageMonitor.setPremiumSmsPermission(packageName, permission); 1756 } 1757 getUsageMonitor()1758 public SmsUsageMonitor getUsageMonitor() { 1759 return mUsageMonitor; 1760 } 1761 1762 /** 1763 * Handles the sms status report based on the format. 1764 * 1765 * @param format the format. 1766 * @param pdu the pdu of the report. 1767 */ handleSmsStatusReport(String format, byte[] pdu)1768 public void handleSmsStatusReport(String format, byte[] pdu) { 1769 int messageRef; 1770 SMSDispatcher.SmsTracker tracker; 1771 boolean handled = false; 1772 if (isCdmaFormat(format)) { 1773 com.android.internal.telephony.cdma.SmsMessage sms = 1774 com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); 1775 if (sms != null) { 1776 boolean foundIn3GPPMap = false; 1777 messageRef = sms.mMessageRef; 1778 tracker = mDeliveryPendingMapFor3GPP2.get(messageRef); 1779 if (tracker == null) { 1780 // A tracker for this 3GPP2 report may be in the 3GPP map instead if the 1781 // previously submitted SMS was 3GPP format. 1782 // (i.e. Some carriers require that devices receive 3GPP2 SMS also even if IMS 1783 // SMS format is 3GGP.) 1784 tracker = mDeliveryPendingMapFor3GPP.get(messageRef); 1785 if (tracker != null) { 1786 foundIn3GPPMap = true; 1787 } 1788 } 1789 if (tracker != null) { 1790 // The status is composed of an error class (bits 25-24) and a status code 1791 // (bits 23-16). 1792 int errorClass = (sms.getStatus() >> 24) & 0x03; 1793 if (errorClass != ERROR_TEMPORARY) { 1794 // Update the message status (COMPLETE or FAILED) 1795 tracker.updateSentMessageStatus( 1796 mContext, 1797 (errorClass == ERROR_NONE) 1798 ? Sms.STATUS_COMPLETE 1799 : Sms.STATUS_FAILED); 1800 // No longer need to be kept. 1801 if (foundIn3GPPMap) { 1802 mDeliveryPendingMapFor3GPP.remove(messageRef); 1803 } else { 1804 mDeliveryPendingMapFor3GPP2.remove(messageRef); 1805 } 1806 } 1807 handled = triggerDeliveryIntent(tracker, format, pdu); 1808 } 1809 } 1810 } else { 1811 com.android.internal.telephony.gsm.SmsMessage sms = 1812 com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); 1813 if (sms != null) { 1814 messageRef = sms.mMessageRef; 1815 tracker = mDeliveryPendingMapFor3GPP.get(messageRef); 1816 if (tracker != null) { 1817 int tpStatus = sms.getStatus(); 1818 if (tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING) { 1819 // Update the message status (COMPLETE or FAILED) 1820 tracker.updateSentMessageStatus(mContext, tpStatus); 1821 // No longer need to be kept. 1822 mDeliveryPendingMapFor3GPP.remove(messageRef); 1823 } 1824 handled = triggerDeliveryIntent(tracker, format, pdu); 1825 } 1826 } 1827 } 1828 1829 if (!handled) { 1830 Rlog.e(TAG, "handleSmsStatusReport: can not handle the status report!"); 1831 } 1832 } 1833 triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu)1834 private boolean triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, 1835 byte[] pdu) { 1836 PendingIntent intent = tracker.mDeliveryIntent; 1837 Intent fillIn = new Intent(); 1838 fillIn.putExtra("pdu", pdu); 1839 fillIn.putExtra("format", format); 1840 try { 1841 intent.send(mContext, Activity.RESULT_OK, fillIn); 1842 return true; 1843 } catch (CanceledException ex) { 1844 return false; 1845 } 1846 } 1847 1848 /** 1849 * Get InboundSmsHandler for the phone. 1850 */ getInboundSmsHandler(boolean is3gpp2)1851 public InboundSmsHandler getInboundSmsHandler(boolean is3gpp2) { 1852 if (is3gpp2) return mCdmaInboundSmsHandler; 1853 else return mGsmInboundSmsHandler; 1854 } 1855 1856 public interface SmsInjectionCallback { onSmsInjectedResult(int result)1857 void onSmsInjectedResult(int result); 1858 } 1859 dump(FileDescriptor fd, PrintWriter pw, String[] args)1860 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1861 mGsmInboundSmsHandler.dump(fd, pw, args); 1862 mCdmaInboundSmsHandler.dump(fd, pw, args); 1863 mGsmDispatcher.dump(fd, pw, args); 1864 mCdmaDispatcher.dump(fd, pw, args); 1865 mImsSmsDispatcher.dump(fd, pw, args); 1866 } 1867 logd(String msg)1868 private void logd(String msg) { 1869 Rlog.d(TAG, msg); 1870 } 1871 logi(String s)1872 private void logi(String s) { 1873 Rlog.i(TAG + " [" + mPhone.getPhoneId() + "]", s); 1874 } 1875 } 1876