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.app.Activity; 24 import android.app.PendingIntent; 25 import android.app.PendingIntent.CanceledException; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.net.Uri; 31 import android.os.AsyncResult; 32 import android.os.Handler; 33 import android.os.Message; 34 import android.os.UserManager; 35 import android.provider.Telephony.Sms; 36 import android.provider.Telephony.Sms.Intents; 37 import android.telephony.ServiceState; 38 import android.telephony.SmsManager; 39 import android.telephony.SmsMessage; 40 41 import com.android.ims.ImsManager; 42 import com.android.internal.annotations.VisibleForTesting; 43 import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; 44 import com.android.internal.telephony.cdma.CdmaSMSDispatcher; 45 import com.android.internal.telephony.gsm.GsmInboundSmsHandler; 46 import com.android.internal.telephony.gsm.GsmSMSDispatcher; 47 import com.android.telephony.Rlog; 48 49 import java.io.FileDescriptor; 50 import java.io.PrintWriter; 51 import java.util.ArrayList; 52 import java.util.HashMap; 53 54 /** 55 * 56 */ 57 public class SmsDispatchersController extends Handler { 58 private static final String TAG = "SmsDispatchersController"; 59 private static final boolean VDBG = false; // STOPSHIP if true 60 61 /** Radio is ON */ 62 private static final int EVENT_RADIO_ON = 11; 63 64 /** IMS registration/SMS format changed */ 65 private static final int EVENT_IMS_STATE_CHANGED = 12; 66 67 /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */ 68 private static final int EVENT_IMS_STATE_DONE = 13; 69 70 /** Service state changed */ 71 private static final int EVENT_SERVICE_STATE_CHANGED = 14; 72 73 /** Purge old message segments */ 74 private static final int EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY = 15; 75 76 /** User unlocked the device */ 77 private static final int EVENT_USER_UNLOCKED = 16; 78 79 /** InboundSmsHandler exited WaitingState */ 80 protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17; 81 82 /** Delete any partial message segments after being IN_SERVICE for 1 day. */ 83 private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24; 84 /** Constant for invalid time */ 85 private static final long INVALID_TIME = -1; 86 /** Time at which last IN_SERVICE event was received */ 87 private long mLastInServiceTime = INVALID_TIME; 88 /** Current IN_SERVICE duration */ 89 private long mCurrentWaitElapsedDuration = 0; 90 /** Time at which the current PARTIAL_SEGMENT_WAIT_DURATION timer was started */ 91 private long mCurrentWaitStartTime = INVALID_TIME; 92 93 private SMSDispatcher mCdmaDispatcher; 94 private SMSDispatcher mGsmDispatcher; 95 private ImsSmsDispatcher mImsSmsDispatcher; 96 97 private GsmInboundSmsHandler mGsmInboundSmsHandler; 98 private CdmaInboundSmsHandler mCdmaInboundSmsHandler; 99 100 private Phone mPhone; 101 /** Outgoing message counter. Shared by all dispatchers. */ 102 private final SmsUsageMonitor mUsageMonitor; 103 private final CommandsInterface mCi; 104 private final Context mContext; 105 106 /** true if IMS is registered and sms is supported, false otherwise.*/ 107 private boolean mIms = false; 108 private String mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN; 109 110 /** 3GPP format sent messages awaiting a delivery status report. */ 111 private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP = new HashMap<>(); 112 113 /** 3GPP2 format sent messages awaiting a delivery status report. */ 114 private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP2 = 115 new HashMap<>(); 116 117 /** 118 * Puts a delivery pending tracker to the map based on the format. 119 * 120 * @param tracker the tracker awaiting a delivery status report. 121 */ putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker)122 public void putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker) { 123 if (isCdmaFormat(tracker.mFormat)) { 124 mDeliveryPendingMapFor3GPP2.put(tracker.mMessageRef, tracker); 125 } else { 126 mDeliveryPendingMapFor3GPP.put(tracker.mMessageRef, tracker); 127 } 128 } 129 SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor)130 public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, 131 SmsUsageMonitor usageMonitor) { 132 Rlog.d(TAG, "SmsDispatchersController created"); 133 134 mContext = phone.getContext(); 135 mUsageMonitor = usageMonitor; 136 mCi = phone.mCi; 137 mPhone = phone; 138 139 // Create dispatchers, inbound SMS handlers and 140 // broadcast undelivered messages in raw table. 141 mImsSmsDispatcher = new ImsSmsDispatcher(phone, this, ImsManager::getConnector); 142 mCdmaDispatcher = new CdmaSMSDispatcher(phone, this); 143 mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), 144 storageMonitor, phone); 145 mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), 146 storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher); 147 mGsmDispatcher = new GsmSMSDispatcher(phone, this, mGsmInboundSmsHandler); 148 SmsBroadcastUndelivered.initialize(phone.getContext(), 149 mGsmInboundSmsHandler, mCdmaInboundSmsHandler); 150 InboundSmsHandler.registerNewMessageNotificationActionHandler(phone.getContext()); 151 152 mCi.registerForOn(this, EVENT_RADIO_ON, null); 153 mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null); 154 155 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 156 if (userManager.isUserUnlocked()) { 157 if (VDBG) { 158 logd("SmsDispatchersController: user unlocked; registering for service" 159 + "state changed"); 160 } 161 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); 162 resetPartialSegmentWaitTimer(); 163 } else { 164 if (VDBG) { 165 logd("SmsDispatchersController: user locked; waiting for USER_UNLOCKED"); 166 } 167 IntentFilter userFilter = new IntentFilter(); 168 userFilter.addAction(Intent.ACTION_USER_UNLOCKED); 169 mContext.registerReceiver(mBroadcastReceiver, userFilter); 170 } 171 } 172 173 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 174 @Override 175 public void onReceive(final Context context, Intent intent) { 176 Rlog.d(TAG, "Received broadcast " + intent.getAction()); 177 if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 178 sendMessage(obtainMessage(EVENT_USER_UNLOCKED)); 179 } 180 } 181 }; 182 dispose()183 public void dispose() { 184 mCi.unregisterForOn(this); 185 mCi.unregisterForImsNetworkStateChanged(this); 186 mPhone.unregisterForServiceStateChanged(this); 187 mGsmDispatcher.dispose(); 188 mCdmaDispatcher.dispose(); 189 mGsmInboundSmsHandler.dispose(); 190 mCdmaInboundSmsHandler.dispose(); 191 } 192 193 /** 194 * Handles events coming from the phone stack. Overridden from handler. 195 * 196 * @param msg the message to handle 197 */ 198 @Override handleMessage(Message msg)199 public void handleMessage(Message msg) { 200 AsyncResult ar; 201 202 switch (msg.what) { 203 case EVENT_RADIO_ON: 204 case EVENT_IMS_STATE_CHANGED: // received unsol 205 mCi.getImsRegistrationState(this.obtainMessage(EVENT_IMS_STATE_DONE)); 206 break; 207 208 case EVENT_IMS_STATE_DONE: 209 ar = (AsyncResult) msg.obj; 210 211 if (ar.exception == null) { 212 updateImsInfo(ar); 213 } else { 214 Rlog.e(TAG, "IMS State query failed with exp " 215 + ar.exception); 216 } 217 break; 218 219 case EVENT_SERVICE_STATE_CHANGED: 220 case EVENT_SMS_HANDLER_EXITING_WAITING_STATE: 221 reevaluateTimerStatus(); 222 break; 223 224 case EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY: 225 handlePartialSegmentTimerExpiry((Long) msg.obj); 226 break; 227 228 case EVENT_USER_UNLOCKED: 229 if (VDBG) { 230 logd("handleMessage: EVENT_USER_UNLOCKED"); 231 } 232 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); 233 resetPartialSegmentWaitTimer(); 234 break; 235 236 default: 237 if (isCdmaMo()) { 238 mCdmaDispatcher.handleMessage(msg); 239 } else { 240 mGsmDispatcher.handleMessage(msg); 241 } 242 } 243 } 244 reevaluateTimerStatus()245 private void reevaluateTimerStatus() { 246 long currentTime = System.currentTimeMillis(); 247 248 // Remove unhandled timer expiry message. A new message will be posted if needed. 249 removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); 250 // Update timer duration elapsed time (add time since last IN_SERVICE to now). 251 // This is needed for IN_SERVICE as well as OUT_OF_SERVICE because same events can be 252 // received back to back 253 if (mLastInServiceTime != INVALID_TIME) { 254 mCurrentWaitElapsedDuration += (currentTime - mLastInServiceTime); 255 } 256 257 if (VDBG) { 258 logd("reevaluateTimerStatus: currentTime: " + currentTime 259 + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); 260 } 261 262 if (mCurrentWaitElapsedDuration > PARTIAL_SEGMENT_WAIT_DURATION) { 263 // handle this event as timer expiry 264 handlePartialSegmentTimerExpiry(mCurrentWaitStartTime); 265 } else { 266 if (isInService()) { 267 handleInService(currentTime); 268 } else { 269 handleOutOfService(currentTime); 270 } 271 } 272 } 273 handleInService(long currentTime)274 private void handleInService(long currentTime) { 275 if (VDBG) { 276 logd("handleInService: timer expiry in " 277 + (PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration) + "ms"); 278 } 279 280 // initialize mCurrentWaitStartTime if needed 281 if (mCurrentWaitStartTime == INVALID_TIME) mCurrentWaitStartTime = currentTime; 282 283 // Post a message for timer expiry time. mCurrentWaitElapsedDuration is the duration already 284 // elapsed from the timer. 285 sendMessageDelayed( 286 obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), 287 PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration); 288 289 // update mLastInServiceTime as the current time 290 mLastInServiceTime = currentTime; 291 } 292 handleOutOfService(long currentTime)293 private void handleOutOfService(long currentTime) { 294 if (VDBG) { 295 logd("handleOutOfService: currentTime: " + currentTime 296 + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); 297 } 298 299 // mLastInServiceTime is not relevant now since state is OUT_OF_SERVICE; set it to INVALID 300 mLastInServiceTime = INVALID_TIME; 301 } 302 handlePartialSegmentTimerExpiry(long waitTimerStart)303 private void handlePartialSegmentTimerExpiry(long waitTimerStart) { 304 if (mGsmInboundSmsHandler.getCurrentState().getName().equals("WaitingState") 305 || mCdmaInboundSmsHandler.getCurrentState().getName().equals("WaitingState")) { 306 logd("handlePartialSegmentTimerExpiry: ignoring timer expiry as InboundSmsHandler is" 307 + " in WaitingState"); 308 return; 309 } 310 311 if (VDBG) { 312 logd("handlePartialSegmentTimerExpiry: calling scanRawTable()"); 313 } 314 // Timer expired. This indicates that device has been in service for 315 // PARTIAL_SEGMENT_WAIT_DURATION since waitTimerStart. Delete orphaned message segments 316 // older than waitTimerStart. 317 SmsBroadcastUndelivered.scanRawTable(mContext, waitTimerStart); 318 if (VDBG) { 319 logd("handlePartialSegmentTimerExpiry: scanRawTable() done"); 320 } 321 322 resetPartialSegmentWaitTimer(); 323 } 324 resetPartialSegmentWaitTimer()325 private void resetPartialSegmentWaitTimer() { 326 long currentTime = System.currentTimeMillis(); 327 328 removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); 329 if (isInService()) { 330 if (VDBG) { 331 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime 332 + " IN_SERVICE"); 333 } 334 mCurrentWaitStartTime = currentTime; 335 mLastInServiceTime = currentTime; 336 sendMessageDelayed( 337 obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), 338 PARTIAL_SEGMENT_WAIT_DURATION); 339 } else { 340 if (VDBG) { 341 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime 342 + " not IN_SERVICE"); 343 } 344 mCurrentWaitStartTime = INVALID_TIME; 345 mLastInServiceTime = INVALID_TIME; 346 } 347 348 mCurrentWaitElapsedDuration = 0; 349 } 350 isInService()351 private boolean isInService() { 352 ServiceState serviceState = mPhone.getServiceState(); 353 return serviceState != null && serviceState.getState() == ServiceState.STATE_IN_SERVICE; 354 } 355 setImsSmsFormat(int format)356 private void setImsSmsFormat(int format) { 357 switch (format) { 358 case PhoneConstants.PHONE_TYPE_GSM: 359 mImsSmsFormat = SmsConstants.FORMAT_3GPP; 360 break; 361 case PhoneConstants.PHONE_TYPE_CDMA: 362 mImsSmsFormat = SmsConstants.FORMAT_3GPP2; 363 break; 364 default: 365 mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN; 366 break; 367 } 368 } 369 updateImsInfo(AsyncResult ar)370 private void updateImsInfo(AsyncResult ar) { 371 int[] responseArray = (int[]) ar.result; 372 setImsSmsFormat(responseArray[1]); 373 mIms = responseArray[0] == 1 && !SmsConstants.FORMAT_UNKNOWN.equals(mImsSmsFormat); 374 Rlog.d(TAG, "IMS registration state: " + mIms + " format: " + mImsSmsFormat); 375 } 376 377 /** 378 * Inject an SMS PDU into the android platform only if it is class 1. 379 * 380 * @param pdu is the byte array of pdu to be injected into android telephony layer 381 * @param format is the format of SMS pdu (3gpp or 3gpp2) 382 * @param callback if not NULL this callback is triggered when the message is successfully 383 * received by the android telephony layer. This callback is triggered at 384 * the same time an SMS received from radio is responded back. 385 */ 386 @VisibleForTesting injectSmsPdu(byte[] pdu, String format, boolean isOverIms, SmsInjectionCallback callback)387 public void injectSmsPdu(byte[] pdu, String format, boolean isOverIms, 388 SmsInjectionCallback callback) { 389 // TODO We need to decide whether we should allow injecting GSM(3gpp) 390 // SMS pdus when the phone is camping on CDMA(3gpp2) network and vice versa. 391 android.telephony.SmsMessage msg = 392 android.telephony.SmsMessage.createFromPdu(pdu, format); 393 injectSmsPdu(msg, format, callback, false /* ignoreClass */, isOverIms); 394 } 395 396 /** 397 * Inject an SMS PDU into the android platform. 398 * 399 * @param msg is the {@link SmsMessage} to be injected into android telephony layer 400 * @param format is the format of SMS pdu (3gpp or 3gpp2) 401 * @param callback if not NULL this callback is triggered when the message is successfully 402 * received by the android telephony layer. This callback is triggered at 403 * the same time an SMS received from radio is responded back. 404 * @param ignoreClass if set to false, this method will inject class 1 sms only. 405 */ 406 @VisibleForTesting injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, boolean ignoreClass, boolean isOverIms)407 public void injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, 408 boolean ignoreClass, boolean isOverIms) { 409 Rlog.d(TAG, "SmsDispatchersController:injectSmsPdu"); 410 try { 411 if (msg == null) { 412 Rlog.e(TAG, "injectSmsPdu: createFromPdu returned null"); 413 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 414 return; 415 } 416 417 if (!ignoreClass 418 && msg.getMessageClass() != android.telephony.SmsMessage.MessageClass.CLASS_1) { 419 Rlog.e(TAG, "injectSmsPdu: not class 1"); 420 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 421 return; 422 } 423 424 AsyncResult ar = new AsyncResult(callback, msg, null); 425 426 if (format.equals(SmsConstants.FORMAT_3GPP)) { 427 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg 428 + ", format=" + format + "to mGsmInboundSmsHandler"); 429 mGsmInboundSmsHandler.sendMessage( 430 InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, 0, ar); 431 } else if (format.equals(SmsConstants.FORMAT_3GPP2)) { 432 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg 433 + ", format=" + format + "to mCdmaInboundSmsHandler"); 434 mCdmaInboundSmsHandler.sendMessage( 435 InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, 0, ar); 436 } else { 437 // Invalid pdu format. 438 Rlog.e(TAG, "Invalid pdu format: " + format); 439 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 440 } 441 } catch (Exception e) { 442 Rlog.e(TAG, "injectSmsPdu failed: ", e); 443 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 444 } 445 } 446 447 /** 448 * Retry the message along to the radio. 449 * 450 * @param tracker holds the SMS message to send 451 */ sendRetrySms(SMSDispatcher.SmsTracker tracker)452 public void sendRetrySms(SMSDispatcher.SmsTracker tracker) { 453 String oldFormat = tracker.mFormat; 454 boolean retryUsingImsService = false; 455 456 if (!tracker.mUsesImsServiceForIms && mImsSmsDispatcher.isAvailable()) { 457 // If this tracker has not been handled by ImsSmsDispatcher yet and IMS Service is 458 // available now, retry this failed tracker using IMS Service. 459 retryUsingImsService = true; 460 } 461 462 // If retryUsingImsService is true, newFormat will be IMS SMS format. Otherwise, newFormat 463 // will be based on voice technology. 464 String newFormat = 465 retryUsingImsService 466 ? mImsSmsDispatcher.getFormat() 467 : (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()) 468 ? mCdmaDispatcher.getFormat() 469 : mGsmDispatcher.getFormat(); 470 471 Rlog.d(TAG, "old format(" + oldFormat + ") ==> new format (" + newFormat + ")"); 472 if (!oldFormat.equals(newFormat)) { 473 // format didn't match, need to re-encode. 474 HashMap map = tracker.getData(); 475 476 // to re-encode, fields needed are: scAddr, destAddr and text if originally sent as 477 // sendText or data and destPort if originally sent as sendData. 478 if (!(map.containsKey("scAddr") && map.containsKey("destAddr") 479 && (map.containsKey("text") 480 || (map.containsKey("data") && map.containsKey("destPort"))))) { 481 // should never come here... 482 Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!"); 483 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 484 return; 485 } 486 String scAddr = (String) map.get("scAddr"); 487 String destAddr = (String) map.get("destAddr"); 488 if (destAddr == null) { 489 Rlog.e(TAG, "sendRetrySms failed due to null destAddr"); 490 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 491 return; 492 } 493 494 SmsMessageBase.SubmitPduBase pdu = null; 495 // figure out from tracker if this was sendText/Data 496 if (map.containsKey("text")) { 497 String text = (String) map.get("text"); 498 Rlog.d(TAG, "sms failed was text with length: " 499 + (text == null ? null : text.length())); 500 501 if (isCdmaFormat(newFormat)) { 502 pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( 503 scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null); 504 } else { 505 pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( 506 scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null); 507 } 508 } else if (map.containsKey("data")) { 509 byte[] data = (byte[]) map.get("data"); 510 Integer destPort = (Integer) map.get("destPort"); 511 Rlog.d(TAG, "sms failed was data with length: " 512 + (data == null ? null : data.length)); 513 514 if (isCdmaFormat(newFormat)) { 515 pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( 516 scAddr, destAddr, destPort.intValue(), data, 517 (tracker.mDeliveryIntent != null)); 518 } else { 519 pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( 520 scAddr, destAddr, destPort.intValue(), data, 521 (tracker.mDeliveryIntent != null)); 522 } 523 } 524 525 if (pdu == null) { 526 Rlog.e(TAG, String.format("sendRetrySms failed to encode message." 527 + "scAddr: %s, " 528 + "destPort: %s", scAddr, map.get("destPort"))); 529 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 530 return; 531 } 532 // replace old smsc and pdu with newly encoded ones 533 map.put("smsc", pdu.encodedScAddress); 534 map.put("pdu", pdu.encodedMessage); 535 tracker.mFormat = newFormat; 536 } 537 538 SMSDispatcher dispatcher = 539 retryUsingImsService 540 ? mImsSmsDispatcher 541 : (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher; 542 543 dispatcher.sendSms(tracker); 544 } 545 546 /** 547 * SMS over IMS is supported if IMS is registered and SMS is supported on IMS. 548 * 549 * @return true if SMS over IMS is supported via an IMS Service or mIms is true for the older 550 * implementation. Otherwise, false. 551 */ isIms()552 public boolean isIms() { 553 return mImsSmsDispatcher.isAvailable() ? true : mIms; 554 } 555 556 /** 557 * Gets SMS format supported on IMS. 558 * 559 * @return the SMS format from an IMS Service if available. Otherwise, mImsSmsFormat for the 560 * older implementation. 561 */ getImsSmsFormat()562 public String getImsSmsFormat() { 563 return mImsSmsDispatcher.isAvailable() ? mImsSmsDispatcher.getFormat() : mImsSmsFormat; 564 } 565 566 /** 567 * Determines whether or not to use CDMA format for MO SMS. 568 * If SMS over IMS is supported, then format is based on IMS SMS format, 569 * otherwise format is based on current phone type. 570 * 571 * @return true if Cdma format should be used for MO SMS, false otherwise. 572 */ isCdmaMo()573 protected boolean isCdmaMo() { 574 if (!isIms()) { 575 // IMS is not registered, use Voice technology to determine SMS format. 576 return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()); 577 } 578 // IMS is registered with SMS support 579 return isCdmaFormat(getImsSmsFormat()); 580 } 581 582 /** 583 * Determines whether or not format given is CDMA format. 584 * 585 * @param format 586 * @return true if format given is CDMA format, false otherwise. 587 */ isCdmaFormat(String format)588 public boolean isCdmaFormat(String format) { 589 return (mCdmaDispatcher.getFormat().equals(format)); 590 } 591 592 /** 593 * Send a data based SMS to a specific application port. 594 * 595 * @param callingPackage the package name of the calling app 596 * @param destAddr the address to send the message to 597 * @param scAddr is the service center address or null to use 598 * the current default SMSC 599 * @param destPort the port to deliver the message to 600 * @param data the body of the message to send 601 * @param sentIntent if not NULL this <code>PendingIntent</code> is 602 * broadcast when the message is successfully sent, or failed. 603 * The result code will be <code>Activity.RESULT_OK<code> for success, 604 * or one of these errors:<br> 605 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 606 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 607 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 608 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 609 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 610 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 611 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 612 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 613 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 614 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 615 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 616 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 617 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 618 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 619 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 620 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 621 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 622 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 623 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 624 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 625 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 626 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 627 * <code>SmsManager.RESULT_CANCELLED</code><br> 628 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 629 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 630 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 631 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 632 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 633 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 634 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 635 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 636 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 637 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 638 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 639 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 640 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 641 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 642 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 643 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 644 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 645 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 646 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 647 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 648 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 649 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 650 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 651 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 652 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 653 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 654 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 655 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 656 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 657 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 658 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 659 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 660 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 661 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 662 * the sentIntent may include the extra "errorCode" containing a radio technology specific 663 * value, generally only useful for troubleshooting.<br> 664 * The per-application based SMS control checks sentIntent. If sentIntent 665 * is NULL the caller will be checked against all unknown applications, 666 * which cause smaller number of SMS to be sent in checking period. 667 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 668 * broadcast when the message is delivered to the recipient. The 669 * raw pdu of the status report is in the extended data ("pdu"). 670 */ sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)671 protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort, 672 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) { 673 if (mImsSmsDispatcher.isAvailable()) { 674 mImsSmsDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent, 675 deliveryIntent, isForVvm); 676 } else if (isCdmaMo()) { 677 mCdmaDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent, 678 deliveryIntent, isForVvm); 679 } else { 680 mGsmDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent, 681 deliveryIntent, isForVvm); 682 } 683 } 684 685 /** 686 * Send a text based SMS. 687 * 688 * @param destAddr the address to send the message to 689 * @param scAddr is the service center address or null to use 690 * the current default SMSC 691 * @param text the body of the message to send 692 * @param sentIntent if not NULL this <code>PendingIntent</code> is 693 * broadcast when the message is successfully sent, or failed. 694 * The result code will be <code>Activity.RESULT_OK<code> for success, 695 * or one of these errors:<br> 696 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 697 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 698 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 699 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 700 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 701 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 702 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 703 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 704 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 705 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 706 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 707 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 708 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 709 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 710 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 711 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 712 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 713 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 714 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 715 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 716 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 717 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 718 * <code>SmsManager.RESULT_CANCELLED</code><br> 719 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 720 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 721 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 722 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 723 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 724 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 725 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 726 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 727 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 728 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 729 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 730 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 731 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 732 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 733 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 734 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 735 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 736 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 737 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 738 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 739 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 740 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 741 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 742 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 743 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 744 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 745 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 746 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 747 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 748 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 749 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 750 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 751 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 752 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 753 * the sentIntent may include the extra "errorCode" containing a radio technology specific 754 * value, generally only useful for troubleshooting.<br> 755 * The per-application based SMS control checks sentIntent. If sentIntent 756 * is NULL the caller will be checked against all unknown applications, 757 * which cause smaller number of SMS to be sent in checking period. 758 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 759 * broadcast when the message is delivered to the recipient. The 760 * @param messageUri optional URI of the message if it is already stored in the system 761 * @param callingPkg the calling package name 762 * @param persistMessage whether to save the sent message into SMS DB for a 763 * non-default SMS app. 764 * @param priority Priority level of the message 765 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 766 * --------------------------------- 767 * PRIORITY | Level of Priority 768 * --------------------------------- 769 * '00' | Normal 770 * '01' | Interactive 771 * '10' | Urgent 772 * '11' | Emergency 773 * ---------------------------------- 774 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 775 * @param expectMore is a boolean to indicate the sending messages through same link or not. 776 * @param validityPeriod Validity Period of the message in mins. 777 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 778 * Validity Period(Minimum) -> 5 mins 779 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 780 * Any Other values included Negative considered as Invalid Validity Period of the message. 781 */ 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)782 public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, 783 PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, 784 int priority, boolean expectMore, int validityPeriod, boolean isForVvm, 785 long messageId) { 786 if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport(destAddr)) { 787 mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, 788 messageUri, callingPkg, persistMessage, priority, false /*expectMore*/, 789 validityPeriod, isForVvm, messageId); 790 } else { 791 if (isCdmaMo()) { 792 mCdmaDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, 793 messageUri, callingPkg, persistMessage, priority, expectMore, 794 validityPeriod, isForVvm, messageId); 795 } else { 796 mGsmDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, 797 messageUri, callingPkg, persistMessage, priority, expectMore, 798 validityPeriod, isForVvm, messageId); 799 } 800 } 801 } 802 803 /** 804 * Send a multi-part text based SMS. 805 * 806 * @param destAddr the address to send the message to 807 * @param scAddr is the service center address or null to use 808 * the current default SMSC 809 * @param parts an <code>ArrayList</code> of strings that, in order, 810 * comprise the original message 811 * @param sentIntents if not null, an <code>ArrayList</code> of 812 * <code>PendingIntent</code>s (one for each message part) that is 813 * broadcast when the corresponding message part has been sent. 814 * The result code will be <code>Activity.RESULT_OK<code> for success, 815 * or one of these errors:<br> 816 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 817 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 818 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 819 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 820 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 821 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 822 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 823 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 824 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 825 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 826 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 827 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 828 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 829 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 830 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 831 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 832 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 833 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 834 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 835 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 836 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 837 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 838 * <code>SmsManager.RESULT_CANCELLED</code><br> 839 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 840 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 841 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 842 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 843 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 844 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 845 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 846 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 847 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 848 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 849 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 850 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 851 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 852 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 853 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 854 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 855 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 856 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 857 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 858 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 859 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 860 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 861 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 862 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 863 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 864 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 865 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 866 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 867 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 868 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 869 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 870 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 871 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 872 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 873 * the sentIntent may include the extra "errorCode" containing a radio technology specific 874 * value, generally only useful for troubleshooting.<br> 875 * The per-application based SMS control checks sentIntent. If sentIntent 876 * is NULL the caller will be checked against all unknown applications, 877 * which cause smaller number of SMS to be sent in checking period. 878 * @param deliveryIntents if not null, an <code>ArrayList</code> of 879 * <code>PendingIntent</code>s (one for each message part) that is 880 * broadcast when the corresponding message part has been delivered 881 * to the recipient. The raw pdu of the status report is in the 882 * @param messageUri optional URI of the message if it is already stored in the system 883 * @param callingPkg the calling package name 884 * @param persistMessage whether to save the sent message into SMS DB for a 885 * non-default SMS app. 886 * @param priority Priority level of the message 887 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 888 * --------------------------------- 889 * PRIORITY | Level of Priority 890 * --------------------------------- 891 * '00' | Normal 892 * '01' | Interactive 893 * '10' | Urgent 894 * '11' | Emergency 895 * ---------------------------------- 896 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 897 * @param expectMore is a boolean to indicate the sending messages through same link or not. 898 * @param validityPeriod Validity Period of the message in mins. 899 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 900 * Validity Period(Minimum) -> 5 mins 901 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 902 * Any Other values included Negative considered as Invalid Validity Period of the message. 903 * @param messageId An id that uniquely identifies the message requested to be sent. 904 * Used for logging and diagnostics purposes. The id may be 0. 905 * 906 */ 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)907 protected void sendMultipartText(String destAddr, String scAddr, 908 ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, 909 ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, 910 boolean persistMessage, int priority, boolean expectMore, int validityPeriod, 911 long messageId) { 912 if (mImsSmsDispatcher.isAvailable()) { 913 mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, 914 deliveryIntents, messageUri, callingPkg, persistMessage, priority, 915 false /*expectMore*/, validityPeriod, messageId); 916 } else { 917 if (isCdmaMo()) { 918 mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, 919 deliveryIntents, messageUri, callingPkg, persistMessage, priority, 920 expectMore, validityPeriod, messageId); 921 } else { 922 mGsmDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, 923 deliveryIntents, messageUri, callingPkg, persistMessage, priority, 924 expectMore, validityPeriod, messageId); 925 } 926 } 927 } 928 929 /** 930 * Returns the premium SMS permission for the specified package. If the package has never 931 * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN} 932 * will be returned. 933 * @param packageName the name of the package to query permission 934 * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN}, 935 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}, 936 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 937 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 938 */ getPremiumSmsPermission(String packageName)939 public int getPremiumSmsPermission(String packageName) { 940 return mUsageMonitor.getPremiumSmsPermission(packageName); 941 } 942 943 /** 944 * Sets the premium SMS permission for the specified package and save the value asynchronously 945 * to persistent storage. 946 * @param packageName the name of the package to set permission 947 * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}, 948 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 949 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 950 */ setPremiumSmsPermission(String packageName, int permission)951 public void setPremiumSmsPermission(String packageName, int permission) { 952 mUsageMonitor.setPremiumSmsPermission(packageName, permission); 953 } 954 getUsageMonitor()955 public SmsUsageMonitor getUsageMonitor() { 956 return mUsageMonitor; 957 } 958 959 /** 960 * Handles the sms status report based on the format. 961 * 962 * @param format the format. 963 * @param pdu the pdu of the report. 964 */ handleSmsStatusReport(String format, byte[] pdu)965 public void handleSmsStatusReport(String format, byte[] pdu) { 966 int messageRef; 967 SMSDispatcher.SmsTracker tracker; 968 boolean handled = false; 969 if (isCdmaFormat(format)) { 970 com.android.internal.telephony.cdma.SmsMessage sms = 971 com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); 972 if (sms != null) { 973 boolean foundIn3GPPMap = false; 974 messageRef = sms.mMessageRef; 975 tracker = mDeliveryPendingMapFor3GPP2.get(messageRef); 976 if (tracker == null) { 977 // A tracker for this 3GPP2 report may be in the 3GPP map instead if the 978 // previously submitted SMS was 3GPP format. 979 // (i.e. Some carriers require that devices receive 3GPP2 SMS also even if IMS 980 // SMS format is 3GGP.) 981 tracker = mDeliveryPendingMapFor3GPP.get(messageRef); 982 if (tracker != null) { 983 foundIn3GPPMap = true; 984 } 985 } 986 if (tracker != null) { 987 // The status is composed of an error class (bits 25-24) and a status code 988 // (bits 23-16). 989 int errorClass = (sms.getStatus() >> 24) & 0x03; 990 if (errorClass != ERROR_TEMPORARY) { 991 // Update the message status (COMPLETE or FAILED) 992 tracker.updateSentMessageStatus( 993 mContext, 994 (errorClass == ERROR_NONE) 995 ? Sms.STATUS_COMPLETE 996 : Sms.STATUS_FAILED); 997 // No longer need to be kept. 998 if (foundIn3GPPMap) { 999 mDeliveryPendingMapFor3GPP.remove(messageRef); 1000 } else { 1001 mDeliveryPendingMapFor3GPP2.remove(messageRef); 1002 } 1003 } 1004 handled = triggerDeliveryIntent(tracker, format, pdu); 1005 } 1006 } 1007 } else { 1008 com.android.internal.telephony.gsm.SmsMessage sms = 1009 com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); 1010 if (sms != null) { 1011 messageRef = sms.mMessageRef; 1012 tracker = mDeliveryPendingMapFor3GPP.get(messageRef); 1013 if (tracker != null) { 1014 int tpStatus = sms.getStatus(); 1015 if (tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING) { 1016 // Update the message status (COMPLETE or FAILED) 1017 tracker.updateSentMessageStatus(mContext, tpStatus); 1018 // No longer need to be kept. 1019 mDeliveryPendingMapFor3GPP.remove(messageRef); 1020 } 1021 handled = triggerDeliveryIntent(tracker, format, pdu); 1022 } 1023 } 1024 } 1025 1026 if (!handled) { 1027 Rlog.e(TAG, "handleSmsStatusReport: can not handle the status report!"); 1028 } 1029 } 1030 triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu)1031 private boolean triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, 1032 byte[] pdu) { 1033 PendingIntent intent = tracker.mDeliveryIntent; 1034 Intent fillIn = new Intent(); 1035 fillIn.putExtra("pdu", pdu); 1036 fillIn.putExtra("format", format); 1037 try { 1038 intent.send(mContext, Activity.RESULT_OK, fillIn); 1039 return true; 1040 } catch (CanceledException ex) { 1041 return false; 1042 } 1043 } 1044 1045 /** 1046 * Get InboundSmsHandler for the phone. 1047 */ getInboundSmsHandler(boolean is3gpp2)1048 public InboundSmsHandler getInboundSmsHandler(boolean is3gpp2) { 1049 if (is3gpp2) return mCdmaInboundSmsHandler; 1050 else return mGsmInboundSmsHandler; 1051 } 1052 1053 public interface SmsInjectionCallback { onSmsInjectedResult(int result)1054 void onSmsInjectedResult(int result); 1055 } 1056 dump(FileDescriptor fd, PrintWriter pw, String[] args)1057 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1058 mGsmInboundSmsHandler.dump(fd, pw, args); 1059 mCdmaInboundSmsHandler.dump(fd, pw, args); 1060 mGsmDispatcher.dump(fd, pw, args); 1061 mCdmaDispatcher.dump(fd, pw, args); 1062 mImsSmsDispatcher.dump(fd, pw, args); 1063 } 1064 logd(String msg)1065 private void logd(String msg) { 1066 Rlog.d(TAG, msg); 1067 } 1068 } 1069