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