GsmSMSDispatcher.java revision e7c29ee85e324289d247d6e28a8c1a216c3658c4
13eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang/* 23eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * Copyright (C) 2006 The Android Open Source Project 34ea9375a2d02a43671437e0d3d808d85afb30afahhtian * 44ea9375a2d02a43671437e0d3d808d85afb30afahhtian * Licensed under the Apache License, Version 2.0 (the "License"); 53eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * you may not use this file except in compliance with the License. 63eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * You may obtain a copy of the License at 73eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * 83eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * http://www.apache.org/licenses/LICENSE-2.0 93eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * 103eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * Unless required by applicable law or agreed to in writing, software 113eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * distributed under the License is distributed on an "AS IS" BASIS, 123eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * See the License for the specific language governing permissions and 143eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang * limitations under the License. 153eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang */ 163eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang 173eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangpackage com.android.internal.telephony.gsm; 183eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang 193eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.app.Activity; 203eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.app.PendingIntent; 213eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.app.PendingIntent.CanceledException; 223eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.content.Intent; 233eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.net.Uri; 243eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.os.AsyncResult; 253eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.os.Message; 263eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.provider.Telephony.Sms; 273eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.provider.Telephony.Sms.Intents; 283eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.telephony.Rlog; 293eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport android.telephony.ServiceState; 303eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang 313eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.annotations.VisibleForTesting; 323eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.GsmAlphabet; 333eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.ImsSMSDispatcher; 343eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.InboundSmsHandler; 353eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.Phone; 363eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.SMSDispatcher; 373eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.SmsConstants; 383eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.SmsHeader; 393eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.SmsUsageMonitor; 403eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.uicc.IccRecords; 413eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.uicc.IccUtils; 423eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.uicc.UiccCardApplication; 433eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport com.android.internal.telephony.uicc.UiccController; 443eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang 453eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport java.util.HashMap; 463eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport java.util.concurrent.atomic.AtomicBoolean; 473eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport java.util.concurrent.atomic.AtomicInteger; 483eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangimport java.util.concurrent.atomic.AtomicReference; 493eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang 503eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwangpublic final class GsmSMSDispatcher extends SMSDispatcher { 513eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang private static final String TAG = "GsmSMSDispatcher"; 523eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang private static final boolean VDBG = false; 533eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang protected UiccController mUiccController = null; 543eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang private AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>(); 553eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang private AtomicReference<UiccCardApplication> mUiccApplication = 563eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang new AtomicReference<UiccCardApplication>(); 573eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang private GsmInboundSmsHandler mGsmInboundSmsHandler; 583eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang 593eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang /** Status report received */ 603eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang private static final int EVENT_NEW_SMS_STATUS_REPORT = 100; 613eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang 623eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang public GsmSMSDispatcher(Phone phone, SmsUsageMonitor usageMonitor, 633eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang ImsSMSDispatcher imsSMSDispatcher, 643eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang GsmInboundSmsHandler gsmInboundSmsHandler) { 653eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang super(phone, usageMonitor, imsSMSDispatcher); 663eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang mCi.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); 673eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang mGsmInboundSmsHandler = gsmInboundSmsHandler; 683eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang mUiccController = UiccController.getInstance(); 693eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); 703eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang Rlog.d(TAG, "GsmSMSDispatcher created"); 713eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang } 723eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang 733eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang @Override 743eb9473ea9a949badfe06ae61d2d3fcfa53651c7qwang public void dispose() { 75 super.dispose(); 76 mCi.unSetOnSmsStatus(this); 77 mUiccController.unregisterForIccChanged(this); 78 } 79 80 @Override 81 protected String getFormat() { 82 return SmsConstants.FORMAT_3GPP; 83 } 84 85 /** 86 * Handles 3GPP format-specific events coming from the phone stack. 87 * Other events are handled by {@link SMSDispatcher#handleMessage}. 88 * 89 * @param msg the message to handle 90 */ 91 @Override 92 public void handleMessage(Message msg) { 93 switch (msg.what) { 94 case EVENT_NEW_SMS_STATUS_REPORT: 95 handleStatusReport((AsyncResult) msg.obj); 96 break; 97 98 case EVENT_NEW_ICC_SMS: 99 // pass to InboundSmsHandler to process 100 mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, msg.obj); 101 break; 102 103 case EVENT_ICC_CHANGED: 104 onUpdateIccAvailability(); 105 break; 106 107 default: 108 super.handleMessage(msg); 109 } 110 } 111 112 /** 113 * Called when a status report is received. This should correspond to 114 * a previously successful SEND. 115 * 116 * @param ar AsyncResult passed into the message handler. ar.result should 117 * be a String representing the status report PDU, as ASCII hex. 118 */ 119 private void handleStatusReport(AsyncResult ar) { 120 byte[] pdu = (byte[]) ar.result; 121 SmsMessage sms = SmsMessage.newFromCDS(pdu); 122 123 if (sms != null) { 124 int tpStatus = sms.getStatus(); 125 int messageRef = sms.mMessageRef; 126 for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { 127 SmsTracker tracker = deliveryPendingList.get(i); 128 if (tracker.mMessageRef == messageRef) { 129 // Found it. Remove from list and broadcast. 130 if(tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING ) { 131 deliveryPendingList.remove(i); 132 // Update the message status (COMPLETE or FAILED) 133 tracker.updateSentMessageStatus(mContext, tpStatus); 134 } 135 PendingIntent intent = tracker.mDeliveryIntent; 136 Intent fillIn = new Intent(); 137 fillIn.putExtra("pdu", pdu); 138 fillIn.putExtra("format", getFormat()); 139 try { 140 intent.send(mContext, Activity.RESULT_OK, fillIn); 141 } catch (CanceledException ex) {} 142 143 // Only expect to see one tracker matching this messageref 144 break; 145 } 146 } 147 } 148 mCi.acknowledgeLastIncomingGsmSms(true, Intents.RESULT_SMS_HANDLED, null); 149 } 150 151 /** {@inheritDoc} */ 152 @Override 153 protected void sendData(String destAddr, String scAddr, int destPort, 154 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 155 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 156 scAddr, destAddr, destPort, data, (deliveryIntent != null)); 157 if (pdu != null) { 158 HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu); 159 SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), 160 null /*messageUri*/, false /*isExpectMore*/, null /*fullMessageText*/, 161 false /*isText*/, true /*persistMessage*/); 162 163 String carrierPackage = getCarrierAppPackageName(); 164 if (carrierPackage != null) { 165 Rlog.d(TAG, "Found carrier package."); 166 DataSmsSender smsSender = new DataSmsSender(tracker); 167 smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender)); 168 } else { 169 Rlog.v(TAG, "No carrier package."); 170 sendRawPdu(tracker); 171 } 172 } else { 173 Rlog.e(TAG, "GsmSMSDispatcher.sendData(): getSubmitPdu() returned null"); 174 } 175 } 176 177 /** {@inheritDoc} */ 178 @VisibleForTesting 179 @Override 180 public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, 181 PendingIntent deliveryIntent, Uri messageUri, String callingPkg, 182 boolean persistMessage) { 183 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 184 scAddr, destAddr, text, (deliveryIntent != null)); 185 if (pdu != null) { 186 HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu); 187 SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), 188 messageUri, false /*isExpectMore*/, text /*fullMessageText*/, true /*isText*/, 189 persistMessage); 190 191 String carrierPackage = getCarrierAppPackageName(); 192 if (carrierPackage != null) { 193 Rlog.d(TAG, "Found carrier package."); 194 TextSmsSender smsSender = new TextSmsSender(tracker); 195 smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender)); 196 } else { 197 Rlog.v(TAG, "No carrier package."); 198 sendRawPdu(tracker); 199 } 200 } else { 201 Rlog.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null"); 202 } 203 } 204 205 /** {@inheritDoc} */ 206 @Override 207 protected void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) { 208 throw new IllegalStateException("This method must be called only on ImsSMSDispatcher"); 209 } 210 211 /** {@inheritDoc} */ 212 @Override 213 protected GsmAlphabet.TextEncodingDetails calculateLength(CharSequence messageBody, 214 boolean use7bitOnly) { 215 return SmsMessage.calculateLength(messageBody, use7bitOnly); 216 } 217 218 /** {@inheritDoc} */ 219 @Override 220 protected SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress, 221 String message, SmsHeader smsHeader, int encoding, 222 PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart, 223 AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, 224 String fullMessageText) { 225 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, 226 message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader), 227 encoding, smsHeader.languageTable, smsHeader.languageShiftTable); 228 if (pdu != null) { 229 HashMap map = getSmsTrackerMap(destinationAddress, scAddress, 230 message, pdu); 231 return getSmsTracker(map, sentIntent, 232 deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri, 233 smsHeader, !lastPart, fullMessageText, true /*isText*/, 234 false /*persistMessage*/); 235 } else { 236 Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null"); 237 return null; 238 } 239 } 240 241 @Override 242 protected void sendSubmitPdu(SmsTracker tracker) { 243 sendRawPdu(tracker); 244 } 245 246 /** {@inheritDoc} */ 247 @Override 248 protected void sendSms(SmsTracker tracker) { 249 HashMap<String, Object> map = tracker.getData(); 250 251 byte pdu[] = (byte[]) map.get("pdu"); 252 253 if (tracker.mRetryCount > 0) { 254 Rlog.d(TAG, "sendSms: " 255 + " mRetryCount=" + tracker.mRetryCount 256 + " mMessageRef=" + tracker.mMessageRef 257 + " SS=" + mPhone.getServiceState().getState()); 258 259 // per TS 23.040 Section 9.2.3.6: If TP-MTI SMS-SUBMIT (0x01) type 260 // TP-RD (bit 2) is 1 for retry 261 // and TP-MR is set to previously failed sms TP-MR 262 if (((0x01 & pdu[0]) == 0x01)) { 263 pdu[0] |= 0x04; // TP-RD 264 pdu[1] = (byte) tracker.mMessageRef; // TP-MR 265 } 266 } 267 Rlog.d(TAG, "sendSms: " 268 + " isIms()=" + isIms() 269 + " mRetryCount=" + tracker.mRetryCount 270 + " mImsRetry=" + tracker.mImsRetry 271 + " mMessageRef=" + tracker.mMessageRef 272 + " SS=" + mPhone.getServiceState().getState()); 273 274 sendSmsByPstn(tracker); 275 } 276 277 /** {@inheritDoc} */ 278 @Override 279 protected void sendSmsByPstn(SmsTracker tracker) { 280 int ss = mPhone.getServiceState().getState(); 281 // if sms over IMS is not supported on data and voice is not available... 282 if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { 283 tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/); 284 return; 285 } 286 287 HashMap<String, Object> map = tracker.getData(); 288 289 byte smsc[] = (byte[]) map.get("smsc"); 290 byte[] pdu = (byte[]) map.get("pdu"); 291 Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); 292 293 // sms over gsm is used: 294 // if sms over IMS is not supported AND 295 // this is not a retry case after sms over IMS failed 296 // indicated by mImsRetry > 0 297 if (0 == tracker.mImsRetry && !isIms()) { 298 if (tracker.mRetryCount > 0) { 299 // per TS 23.040 Section 9.2.3.6: If TP-MTI SMS-SUBMIT (0x01) type 300 // TP-RD (bit 2) is 1 for retry 301 // and TP-MR is set to previously failed sms TP-MR 302 if (((0x01 & pdu[0]) == 0x01)) { 303 pdu[0] |= 0x04; // TP-RD 304 pdu[1] = (byte) tracker.mMessageRef; // TP-MR 305 } 306 } 307 if (tracker.mRetryCount == 0 && tracker.mExpectMore) { 308 mCi.sendSMSExpectMore(IccUtils.bytesToHexString(smsc), 309 IccUtils.bytesToHexString(pdu), reply); 310 } else { 311 mCi.sendSMS(IccUtils.bytesToHexString(smsc), 312 IccUtils.bytesToHexString(pdu), reply); 313 } 314 } else { 315 mCi.sendImsGsmSms(IccUtils.bytesToHexString(smsc), 316 IccUtils.bytesToHexString(pdu), tracker.mImsRetry, 317 tracker.mMessageRef, reply); 318 // increment it here, so in case of SMS_FAIL_RETRY over IMS 319 // next retry will be sent using IMS request again. 320 tracker.mImsRetry++; 321 } 322 } 323 324 protected UiccCardApplication getUiccCardApplication() { 325 Rlog.d(TAG, "GsmSMSDispatcher: subId = " + mPhone.getSubId() 326 + " slotId = " + mPhone.getPhoneId()); 327 return mUiccController.getUiccCardApplication(mPhone.getPhoneId(), 328 UiccController.APP_FAM_3GPP); 329 } 330 331 private void onUpdateIccAvailability() { 332 if (mUiccController == null ) { 333 return; 334 } 335 336 UiccCardApplication newUiccApplication = getUiccCardApplication(); 337 338 UiccCardApplication app = mUiccApplication.get(); 339 if (app != newUiccApplication) { 340 if (app != null) { 341 Rlog.d(TAG, "Removing stale icc objects."); 342 if (mIccRecords.get() != null) { 343 mIccRecords.get().unregisterForNewSms(this); 344 } 345 mIccRecords.set(null); 346 mUiccApplication.set(null); 347 } 348 if (newUiccApplication != null) { 349 Rlog.d(TAG, "New Uicc application found"); 350 mUiccApplication.set(newUiccApplication); 351 mIccRecords.set(newUiccApplication.getIccRecords()); 352 if (mIccRecords.get() != null) { 353 mIccRecords.get().registerForNewSms(this, EVENT_NEW_ICC_SMS, null); 354 } 355 } 356 } 357 } 358} 359