ImsSMSDispatcher.java revision d2feaf918ab0c1173d4ada182532e48d0c0d3f77
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.internal.telephony; 19 20import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE; 21 22import java.util.ArrayList; 23import java.util.HashMap; 24 25import android.app.PendingIntent; 26import android.app.PendingIntent.CanceledException; 27import android.os.AsyncResult; 28import android.os.Message; 29import android.provider.Telephony.Sms.Intents; 30import android.telephony.Rlog; 31 32import com.android.internal.telephony.cdma.CdmaSMSDispatcher; 33import com.android.internal.telephony.gsm.GsmSMSDispatcher; 34import com.android.internal.telephony.InboundSmsHandler; 35import com.android.internal.telephony.gsm.GsmInboundSmsHandler; 36import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; 37import com.android.internal.telephony.SmsBroadcastUndelivered; 38 39public final class ImsSMSDispatcher extends SMSDispatcher { 40 private static final String TAG = "RIL_ImsSms"; 41 42 private SMSDispatcher mCdmaDispatcher; 43 private SMSDispatcher mGsmDispatcher; 44 45 GsmInboundSmsHandler mGsmInboundSmsHandler; 46 CdmaInboundSmsHandler mCdmaInboundSmsHandler; 47 48 /** true if IMS is registered and sms is supported, false otherwise.*/ 49 private boolean mIms = false; 50 private String mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN; 51 52 public ImsSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor, 53 SmsUsageMonitor usageMonitor) { 54 super(phone, usageMonitor); 55 Rlog.d(TAG, "ImsSMSDispatcher created"); 56 57 // Create dispatchers, inbound SMS handlers and broadcast 58 // undelivered messages in raw table. 59 mCdmaDispatcher = new CdmaSMSDispatcher(phone, 60 storageMonitor, usageMonitor, this); 61 mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), 62 storageMonitor, phone); 63 mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), 64 storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher); 65 mGsmDispatcher = new GsmSMSDispatcher(phone, 66 storageMonitor, usageMonitor, this, mGsmInboundSmsHandler); 67 Thread broadcastThread = new Thread(new SmsBroadcastUndelivered(phone.getContext(), 68 mGsmInboundSmsHandler, mCdmaInboundSmsHandler)); 69 broadcastThread.start(); 70 71 mCi.registerForOn(this, EVENT_RADIO_ON, null); 72 mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null); 73 } 74 75 /* Updates the phone object when there is a change */ 76 @Override 77 protected void updatePhoneObject(PhoneBase phone) { 78 Rlog.d(TAG, "In IMS updatePhoneObject "); 79 super.updatePhoneObject(phone); 80 mCdmaDispatcher.updatePhoneObject(phone); 81 mGsmDispatcher.updatePhoneObject(phone); 82 mGsmInboundSmsHandler.updatePhoneObject(phone); 83 mCdmaInboundSmsHandler.updatePhoneObject(phone); 84 } 85 86 public void dispose() { 87 mCi.unregisterForOn(this); 88 mCi.unregisterForImsNetworkStateChanged(this); 89 mGsmDispatcher.dispose(); 90 mCdmaDispatcher.dispose(); 91 mGsmInboundSmsHandler.dispose(); 92 mCdmaInboundSmsHandler.dispose(); 93 } 94 95 /** 96 * Handles events coming from the phone stack. Overridden from handler. 97 * 98 * @param msg the message to handle 99 */ 100 @Override 101 public void handleMessage(Message msg) { 102 AsyncResult ar; 103 104 switch (msg.what) { 105 case EVENT_RADIO_ON: 106 case EVENT_IMS_STATE_CHANGED: // received unsol 107 mCi.getImsRegistrationState(this.obtainMessage(EVENT_IMS_STATE_DONE)); 108 break; 109 110 case EVENT_IMS_STATE_DONE: 111 ar = (AsyncResult) msg.obj; 112 113 if (ar.exception == null) { 114 updateImsInfo(ar); 115 } else { 116 Rlog.e(TAG, "IMS State query failed with exp " 117 + ar.exception); 118 } 119 break; 120 121 default: 122 super.handleMessage(msg); 123 } 124 } 125 126 private void setImsSmsFormat(int format) { 127 // valid format? 128 switch (format) { 129 case PhoneConstants.PHONE_TYPE_GSM: 130 mImsSmsFormat = "3gpp"; 131 break; 132 case PhoneConstants.PHONE_TYPE_CDMA: 133 mImsSmsFormat = "3gpp2"; 134 break; 135 default: 136 mImsSmsFormat = "unknown"; 137 break; 138 } 139 } 140 141 private void updateImsInfo(AsyncResult ar) { 142 int[] responseArray = (int[])ar.result; 143 144 mIms = false; 145 if (responseArray[0] == 1) { // IMS is registered 146 Rlog.d(TAG, "IMS is registered!"); 147 mIms = true; 148 } else { 149 Rlog.d(TAG, "IMS is NOT registered!"); 150 } 151 152 setImsSmsFormat(responseArray[1]); 153 154 if (("unknown".equals(mImsSmsFormat))) { 155 Rlog.e(TAG, "IMS format was unknown!"); 156 // failed to retrieve valid IMS SMS format info, set IMS to unregistered 157 mIms = false; 158 } 159 } 160 161 @Override 162 protected void sendData(String destAddr, String scAddr, int destPort, 163 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 164 if (isCdmaMo()) { 165 mCdmaDispatcher.sendData(destAddr, scAddr, destPort, 166 data, sentIntent, deliveryIntent); 167 } else { 168 mGsmDispatcher.sendData(destAddr, scAddr, destPort, 169 data, sentIntent, deliveryIntent); 170 } 171 } 172 173 @Override 174 protected void sendMultipartText(String destAddr, String scAddr, 175 ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, 176 ArrayList<PendingIntent> deliveryIntents) { 177 if (isCdmaMo()) { 178 mCdmaDispatcher.sendMultipartText(destAddr, scAddr, 179 parts, sentIntents, deliveryIntents); 180 } else { 181 mGsmDispatcher.sendMultipartText(destAddr, scAddr, 182 parts, sentIntents, deliveryIntents); 183 } 184 } 185 186 @Override 187 protected void sendSms(SmsTracker tracker) { 188 // sendSms is a helper function to other send functions, sendText/Data... 189 // it is not part of ISms.stub 190 Rlog.e(TAG, "sendSms should never be called from here!"); 191 } 192 193 @Override 194 protected void sendText(String destAddr, String scAddr, String text, 195 PendingIntent sentIntent, PendingIntent deliveryIntent) { 196 Rlog.d(TAG, "sendText"); 197 if (isCdmaMo()) { 198 mCdmaDispatcher.sendText(destAddr, scAddr, 199 text, sentIntent, deliveryIntent); 200 } else { 201 mGsmDispatcher.sendText(destAddr, scAddr, 202 text, sentIntent, deliveryIntent); 203 } 204 } 205 206 @Override 207 public void sendRetrySms(SmsTracker tracker) { 208 String oldFormat = tracker.mFormat; 209 210 // newFormat will be based on voice technology 211 String newFormat = 212 (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()) ? 213 mCdmaDispatcher.getFormat() : 214 mGsmDispatcher.getFormat(); 215 216 // was previously sent sms format match with voice tech? 217 if (oldFormat.equals(newFormat)) { 218 if (isCdmaFormat(newFormat)) { 219 Rlog.d(TAG, "old format matched new format (cdma)"); 220 mCdmaDispatcher.sendSms(tracker); 221 return; 222 } else { 223 Rlog.d(TAG, "old format matched new format (gsm)"); 224 mGsmDispatcher.sendSms(tracker); 225 return; 226 } 227 } 228 229 // format didn't match, need to re-encode. 230 HashMap map = tracker.mData; 231 232 // to re-encode, fields needed are: scAddr, destAddr, and 233 // text if originally sent as sendText or 234 // data and destPort if originally sent as sendData. 235 if (!( map.containsKey("scAddr") && map.containsKey("destAddr") && 236 ( map.containsKey("text") || 237 (map.containsKey("data") && map.containsKey("destPort"))))) { 238 // should never come here... 239 Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!"); 240 if (tracker.mSentIntent != null) { 241 int error = RESULT_ERROR_GENERIC_FAILURE; 242 // Done retrying; return an error to the app. 243 try { 244 tracker.mSentIntent.send(mContext, error, null); 245 } catch (CanceledException ex) {} 246 } 247 return; 248 } 249 String scAddr = (String)map.get("scAddr"); 250 String destAddr = (String)map.get("destAddr"); 251 252 SmsMessageBase.SubmitPduBase pdu = null; 253 // figure out from tracker if this was sendText/Data 254 if (map.containsKey("text")) { 255 Rlog.d(TAG, "sms failed was text"); 256 String text = (String)map.get("text"); 257 258 if (isCdmaFormat(newFormat)) { 259 Rlog.d(TAG, "old format (gsm) ==> new format (cdma)"); 260 pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( 261 scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null); 262 } else { 263 Rlog.d(TAG, "old format (cdma) ==> new format (gsm)"); 264 pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( 265 scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null); 266 } 267 } else if (map.containsKey("data")) { 268 Rlog.d(TAG, "sms failed was data"); 269 byte[] data = (byte[])map.get("data"); 270 Integer destPort = (Integer)map.get("destPort"); 271 272 if (isCdmaFormat(newFormat)) { 273 Rlog.d(TAG, "old format (gsm) ==> new format (cdma)"); 274 pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( 275 scAddr, destAddr, destPort.intValue(), data, 276 (tracker.mDeliveryIntent != null)); 277 } else { 278 Rlog.d(TAG, "old format (cdma) ==> new format (gsm)"); 279 pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( 280 scAddr, destAddr, destPort.intValue(), data, 281 (tracker.mDeliveryIntent != null)); 282 } 283 } 284 285 // replace old smsc and pdu with newly encoded ones 286 map.put("smsc", pdu.encodedScAddress); 287 map.put("pdu", pdu.encodedMessage); 288 289 SMSDispatcher dispatcher = (isCdmaFormat(newFormat)) ? 290 mCdmaDispatcher : mGsmDispatcher; 291 292 tracker.mFormat = dispatcher.getFormat(); 293 dispatcher.sendSms(tracker); 294 } 295 296 @Override 297 protected String getFormat() { 298 // this function should be defined in Gsm/CdmaDispatcher. 299 Rlog.e(TAG, "getFormat should never be called from here!"); 300 return "unknown"; 301 } 302 303 @Override 304 protected GsmAlphabet.TextEncodingDetails calculateLength( 305 CharSequence messageBody, boolean use7bitOnly) { 306 Rlog.e(TAG, "Error! Not implemented for IMS."); 307 return null; 308 } 309 310 @Override 311 protected void sendNewSubmitPdu(String destinationAddress, String scAddress, String message, 312 SmsHeader smsHeader, int format, PendingIntent sentIntent, 313 PendingIntent deliveryIntent, boolean lastPart) { 314 Rlog.e(TAG, "Error! Not implemented for IMS."); 315 } 316 317 @Override 318 public boolean isIms() { 319 return mIms; 320 } 321 322 @Override 323 public String getImsSmsFormat() { 324 return mImsSmsFormat; 325 } 326 327 /** 328 * Determines whether or not to use CDMA format for MO SMS. 329 * If SMS over IMS is supported, then format is based on IMS SMS format, 330 * otherwise format is based on current phone type. 331 * 332 * @return true if Cdma format should be used for MO SMS, false otherwise. 333 */ 334 private boolean isCdmaMo() { 335 if (!isIms()) { 336 // IMS is not registered, use Voice technology to determine SMS format. 337 return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()); 338 } 339 // IMS is registered with SMS support 340 return isCdmaFormat(mImsSmsFormat); 341 } 342 343 /** 344 * Determines whether or not format given is CDMA format. 345 * 346 * @param format 347 * @return true if format given is CDMA format, false otherwise. 348 */ 349 private boolean isCdmaFormat(String format) { 350 return (mCdmaDispatcher.getFormat().equals(format)); 351 } 352} 353