CdmaSMSDispatcher.java revision c9394399180abbc32d04f6a3652ce22d5931e0b8
1/* 2 * Copyright (C) 2008 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 17package com.android.internal.telephony.cdma; 18 19import android.app.Activity; 20import android.app.AppOpsManager; 21import android.app.PendingIntent; 22import android.app.PendingIntent.CanceledException; 23import android.content.BroadcastReceiver; 24import android.content.Intent; 25import android.net.Uri; 26import android.os.Message; 27import android.os.SystemProperties; 28import android.provider.Telephony.Sms; 29import android.provider.Telephony.Sms.Intents; 30import android.telephony.Rlog; 31import android.telephony.SmsManager; 32 33import com.android.internal.telephony.GsmAlphabet; 34import com.android.internal.telephony.ImsSMSDispatcher; 35import com.android.internal.telephony.PhoneBase; 36import com.android.internal.telephony.SMSDispatcher; 37import com.android.internal.telephony.SmsConstants; 38import com.android.internal.telephony.SmsHeader; 39import com.android.internal.telephony.SmsUsageMonitor; 40import com.android.internal.telephony.TelephonyProperties; 41import com.android.internal.telephony.cdma.sms.UserData; 42 43import java.util.HashMap; 44import java.util.concurrent.atomic.AtomicBoolean; 45import java.util.concurrent.atomic.AtomicInteger; 46 47public class CdmaSMSDispatcher extends SMSDispatcher { 48 private static final String TAG = "CdmaSMSDispatcher"; 49 private static final boolean VDBG = false; 50 51 public CdmaSMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor, 52 ImsSMSDispatcher imsSMSDispatcher) { 53 super(phone, usageMonitor, imsSMSDispatcher); 54 Rlog.d(TAG, "CdmaSMSDispatcher created"); 55 } 56 57 @Override 58 protected String getFormat() { 59 return SmsConstants.FORMAT_3GPP2; 60 } 61 62 /** 63 * Send the SMS status report to the dispatcher thread to process. 64 * @param sms the CDMA SMS message containing the status report 65 */ 66 void sendStatusReportMessage(SmsMessage sms) { 67 if (VDBG) Rlog.d(TAG, "sending EVENT_HANDLE_STATUS_REPORT message"); 68 sendMessage(obtainMessage(EVENT_HANDLE_STATUS_REPORT, sms)); 69 } 70 71 @Override 72 protected void handleStatusReport(Object o) { 73 if (o instanceof SmsMessage) { 74 if (VDBG) Rlog.d(TAG, "calling handleCdmaStatusReport()"); 75 handleCdmaStatusReport((SmsMessage) o); 76 } else { 77 Rlog.e(TAG, "handleStatusReport() called for object type " + o.getClass().getName()); 78 } 79 } 80 81 /** 82 * Called from parent class to handle status report from {@code CdmaInboundSmsHandler}. 83 * @param sms the CDMA SMS message to process 84 */ 85 void handleCdmaStatusReport(SmsMessage sms) { 86 for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { 87 SmsTracker tracker = deliveryPendingList.get(i); 88 if (tracker.mMessageRef == sms.mMessageRef) { 89 // Found it. Remove from list and broadcast. 90 deliveryPendingList.remove(i); 91 // Update the message status (COMPLETE) 92 tracker.updateSentMessageStatus(mContext, Sms.STATUS_COMPLETE); 93 94 PendingIntent intent = tracker.mDeliveryIntent; 95 Intent fillIn = new Intent(); 96 fillIn.putExtra("pdu", sms.getPdu()); 97 fillIn.putExtra("format", getFormat()); 98 try { 99 intent.send(mContext, Activity.RESULT_OK, fillIn); 100 } catch (CanceledException ex) {} 101 break; // Only expect to see one tracker matching this message. 102 } 103 } 104 } 105 106 /** {@inheritDoc} */ 107 @Override 108 protected void sendData(String destAddr, String scAddr, int destPort, 109 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 110 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 111 scAddr, destAddr, destPort, data, (deliveryIntent != null)); 112 HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu); 113 SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), 114 null/*messageUri*/); 115 sendSubmitPdu(tracker); 116 } 117 118 /** {@inheritDoc} */ 119 @Override 120 protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, 121 PendingIntent deliveryIntent, Uri messageUri, String callingPkg) { 122 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 123 scAddr, destAddr, text, (deliveryIntent != null), null); 124 if (pdu != null) { 125 if (messageUri == null) { 126 messageUri = writeOutboxMessage( 127 getSubId(), 128 destAddr, 129 text, 130 deliveryIntent != null, 131 callingPkg); 132 } else { 133 moveToOutbox(getSubId(), messageUri, callingPkg); 134 } 135 HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu); 136 SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), 137 messageUri); 138 sendSubmitPdu(tracker); 139 } else { 140 Rlog.e(TAG, "CdmaSMSDispatcher.sendText(): getSubmitPdu() returned null"); 141 } 142 } 143 144 /** {@inheritDoc} */ 145 @Override 146 protected void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) { 147 throw new IllegalStateException("This method must be called only on ImsSMSDispatcher"); 148 } 149 150 /** {@inheritDoc} */ 151 @Override 152 protected GsmAlphabet.TextEncodingDetails calculateLength(CharSequence messageBody, 153 boolean use7bitOnly) { 154 return SmsMessage.calculateLength(messageBody, use7bitOnly); 155 } 156 157 /** {@inheritDoc} */ 158 @Override 159 protected void sendNewSubmitPdu(String destinationAddress, String scAddress, 160 String message, SmsHeader smsHeader, int encoding, 161 PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart, 162 AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri) { 163 UserData uData = new UserData(); 164 uData.payloadStr = message; 165 uData.userDataHeader = smsHeader; 166 if (encoding == SmsConstants.ENCODING_7BIT) { 167 uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; 168 } else { // assume UTF-16 169 uData.msgEncoding = UserData.ENCODING_UNICODE_16; 170 } 171 uData.msgEncodingSet = true; 172 173 /* By setting the statusReportRequested bit only for the 174 * last message fragment, this will result in only one 175 * callback to the sender when that last fragment delivery 176 * has been acknowledged. */ 177 SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destinationAddress, 178 uData, (deliveryIntent != null) && lastPart); 179 180 HashMap map = getSmsTrackerMap(destinationAddress, scAddress, 181 message, submitPdu); 182 SmsTracker tracker = getSmsTracker(map, sentIntent, 183 deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri); 184 sendSubmitPdu(tracker); 185 } 186 187 protected void sendSubmitPdu(SmsTracker tracker) { 188 if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false)) { 189 if (VDBG) { 190 Rlog.d(TAG, "Block SMS in Emergency Callback mode"); 191 } 192 tracker.onFailed(mContext, SmsManager.RESULT_ERROR_NO_SERVICE, 0/*errorCode*/); 193 return; 194 } 195 sendRawPdu(tracker); 196 } 197 198 /** {@inheritDoc} */ 199 @Override 200 protected void sendSms(SmsTracker tracker) { 201 HashMap<String, Object> map = tracker.mData; 202 203 // byte[] smsc = (byte[]) map.get("smsc"); // unused for CDMA 204 byte[] pdu = (byte[]) map.get("pdu"); 205 206 Rlog.d(TAG, "sendSms: " 207 + " isIms()=" + isIms() 208 + " mRetryCount=" + tracker.mRetryCount 209 + " mImsRetry=" + tracker.mImsRetry 210 + " mMessageRef=" + tracker.mMessageRef 211 + " SS=" + mPhone.getServiceState().getState()); 212 213 // FIX this once the carrier app and SIM restricted API is finalized. 214 // We should direct the intent to only the default carrier app. 215 216 // Send SMS via the carrier app. 217 BroadcastReceiver resultReceiver = new SMSDispatcherReceiver(tracker); 218 219 // Direct the intent to only the default carrier app. 220 Intent intent = new Intent(Intents.SMS_SEND_ACTION); 221 intent.setPackage(getCarrierAppPackageName(intent)); 222 intent.putExtra("pdu", pdu); 223 intent.putExtra("format", getFormat()); 224 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); 225 Rlog.d(TAG, "Sending SMS by carrier app."); 226 227 mContext.sendOrderedBroadcast(intent, android.Manifest.permission.RECEIVE_SMS, 228 AppOpsManager.OP_RECEIVE_SMS, resultReceiver, 229 null, Activity.RESULT_CANCELED, null, null); 230 } 231 232 /** {@inheritDoc} */ 233 @Override 234 protected void updateSmsSendStatus(int messageRef, boolean success) { 235 // This function should be defined in ImsDispatcher. 236 Rlog.e(TAG, "updateSmsSendStatus should never be called from here!"); 237 } 238 239 /** {@inheritDoc} */ 240 @Override 241 protected void sendSmsByPstn(SmsTracker tracker) { 242 Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); 243 byte[] pdu = (byte[]) tracker.mData.get("pdu"); 244 245 // sms over cdma is used: 246 // if sms over IMS is not supported AND 247 // this is not a retry case after sms over IMS failed 248 // indicated by mImsRetry > 0 249 if (0 == tracker.mImsRetry && !isIms()) { 250 mCi.sendCdmaSms(pdu, reply); 251 } else { 252 mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply); 253 // increment it here, so in case of SMS_FAIL_RETRY over IMS 254 // next retry will be sent using IMS request again. 255 tracker.mImsRetry++; 256 } 257 } 258} 259