CdmaSMSDispatcher.java revision 112c36a6080b6902925d317218acc14183e29842
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.ComponentName; 25import android.content.Context; 26import android.content.Intent; 27import android.os.AsyncResult; 28import android.os.Message; 29import android.os.SystemProperties; 30import android.provider.Telephony.Sms; 31import android.provider.Telephony.Sms.Intents; 32import android.telephony.Rlog; 33import android.telephony.SmsManager; 34 35import com.android.internal.telephony.GsmAlphabet; 36import com.android.internal.telephony.ImsSMSDispatcher; 37import com.android.internal.telephony.PhoneBase; 38import com.android.internal.telephony.SMSDispatcher; 39import com.android.internal.telephony.SmsConstants; 40import com.android.internal.telephony.SmsHeader; 41import com.android.internal.telephony.SmsUsageMonitor; 42import com.android.internal.telephony.TelephonyProperties; 43import com.android.internal.telephony.cdma.sms.UserData; 44 45import java.util.HashMap; 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, 114 getFormat()); 115 sendSubmitPdu(tracker); 116 } 117 118 /** {@inheritDoc} */ 119 @Override 120 protected void sendText(String destAddr, String scAddr, String text, 121 PendingIntent sentIntent, PendingIntent deliveryIntent) { 122 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 123 scAddr, destAddr, text, (deliveryIntent != null), null); 124 HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu); 125 SmsTracker tracker = getSmsTracker(map, sentIntent, 126 deliveryIntent, getFormat()); 127 sendSubmitPdu(tracker); 128 } 129 130 /** {@inheritDoc} */ 131 @Override 132 protected GsmAlphabet.TextEncodingDetails calculateLength(CharSequence messageBody, 133 boolean use7bitOnly) { 134 return SmsMessage.calculateLength(messageBody, use7bitOnly); 135 } 136 137 /** {@inheritDoc} */ 138 @Override 139 protected void sendNewSubmitPdu(String destinationAddress, String scAddress, 140 String message, SmsHeader smsHeader, int encoding, 141 PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) { 142 UserData uData = new UserData(); 143 uData.payloadStr = message; 144 uData.userDataHeader = smsHeader; 145 if (encoding == SmsConstants.ENCODING_7BIT) { 146 uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; 147 } else { // assume UTF-16 148 uData.msgEncoding = UserData.ENCODING_UNICODE_16; 149 } 150 uData.msgEncodingSet = true; 151 152 /* By setting the statusReportRequested bit only for the 153 * last message fragment, this will result in only one 154 * callback to the sender when that last fragment delivery 155 * has been acknowledged. */ 156 SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destinationAddress, 157 uData, (deliveryIntent != null) && lastPart); 158 159 HashMap map = getSmsTrackerMap(destinationAddress, scAddress, 160 message, submitPdu); 161 SmsTracker tracker = getSmsTracker(map, sentIntent, 162 deliveryIntent, getFormat()); 163 sendSubmitPdu(tracker); 164 } 165 166 protected void sendSubmitPdu(SmsTracker tracker) { 167 if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false)) { 168 if (tracker.mSentIntent != null) { 169 try { 170 tracker.mSentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE); 171 } catch (CanceledException ex) {} 172 } 173 if (VDBG) { 174 Rlog.d(TAG, "Block SMS in Emergency Callback mode"); 175 } 176 return; 177 } 178 sendRawPdu(tracker); 179 } 180 181 /** {@inheritDoc} */ 182 @Override 183 protected void sendSms(SmsTracker tracker) { 184 HashMap<String, Object> map = tracker.mData; 185 186 // byte[] smsc = (byte[]) map.get("smsc"); // unused for CDMA 187 byte[] pdu = (byte[]) map.get("pdu"); 188 189 Rlog.d(TAG, "sendSms: " 190 + " isIms()=" + isIms() 191 + " mRetryCount=" + tracker.mRetryCount 192 + " mImsRetry=" + tracker.mImsRetry 193 + " mMessageRef=" + tracker.mMessageRef 194 + " SS=" + mPhone.getServiceState().getState()); 195 196 // FIX this once the carrier app and SIM restricted API is finalized. 197 // We should direct the intent to only the default carrier app. 198 199 // Send SMS via the carrier app. 200 BroadcastReceiver resultReceiver = new SMSDispatcherReceiver(tracker); 201 202 // Direct the intent to only the default carrier app. 203 Intent intent = new Intent(Intents.SMS_SEND_ACTION); 204 intent.putExtra("pdu", pdu); 205 intent.putExtra("format", getFormat()); 206 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); 207 Rlog.d(TAG, "Sending SMS by carrier app."); 208 209 mContext.sendOrderedBroadcast(intent, android.Manifest.permission.RECEIVE_SMS, 210 AppOpsManager.OP_RECEIVE_SMS, resultReceiver, 211 null, Activity.RESULT_CANCELED, null, null); 212 } 213 214 /** {@inheritDoc} */ 215 @Override 216 protected void updateSmsSendStatus(int messageRef, boolean success) { 217 // This function should be defined in ImsDispatcher. 218 Rlog.e(TAG, "updateSmsSendStatus should never be called from here!"); 219 } 220 221 /** {@inheritDoc} */ 222 @Override 223 protected void sendSmsByPstn(SmsTracker tracker) { 224 Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); 225 byte[] pdu = (byte[]) tracker.mData.get("pdu"); 226 227 // sms over cdma is used: 228 // if sms over IMS is not supported AND 229 // this is not a retry case after sms over IMS failed 230 // indicated by mImsRetry > 0 231 if (0 == tracker.mImsRetry && !isIms()) { 232 mCi.sendCdmaSms(pdu, reply); 233 } else { 234 mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply); 235 // increment it here, so in case of SMS_FAIL_RETRY over IMS 236 // next retry will be sent using IMS request again. 237 tracker.mImsRetry++; 238 } 239 } 240} 241