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 17 package com.android.internal.telephony.cdma; 18 19 import android.app.Activity; 20 import android.app.PendingIntent; 21 import android.app.PendingIntent.CanceledException; 22 import android.content.Intent; 23 import android.os.Message; 24 import android.os.SystemProperties; 25 import android.provider.Telephony.Sms; 26 import android.telephony.Rlog; 27 import android.telephony.SmsManager; 28 29 import com.android.internal.telephony.GsmAlphabet; 30 import com.android.internal.telephony.ImsSMSDispatcher; 31 import com.android.internal.telephony.PhoneBase; 32 import com.android.internal.telephony.SMSDispatcher; 33 import com.android.internal.telephony.SmsConstants; 34 import com.android.internal.telephony.SmsHeader; 35 import com.android.internal.telephony.SmsUsageMonitor; 36 import com.android.internal.telephony.TelephonyProperties; 37 import com.android.internal.telephony.cdma.sms.UserData; 38 39 import java.util.HashMap; 40 41 public class CdmaSMSDispatcher extends SMSDispatcher { 42 private static final String TAG = "CdmaSMSDispatcher"; 43 private static final boolean VDBG = false; 44 45 public CdmaSMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor, 46 ImsSMSDispatcher imsSMSDispatcher) { 47 super(phone, usageMonitor, imsSMSDispatcher); 48 Rlog.d(TAG, "CdmaSMSDispatcher created"); 49 } 50 51 @Override 52 protected String getFormat() { 53 return SmsConstants.FORMAT_3GPP2; 54 } 55 56 /** 57 * Send the SMS status report to the dispatcher thread to process. 58 * @param sms the CDMA SMS message containing the status report 59 */ 60 void sendStatusReportMessage(SmsMessage sms) { 61 if (VDBG) Rlog.d(TAG, "sending EVENT_HANDLE_STATUS_REPORT message"); 62 sendMessage(obtainMessage(EVENT_HANDLE_STATUS_REPORT, sms)); 63 } 64 65 @Override 66 protected void handleStatusReport(Object o) { 67 if (o instanceof SmsMessage) { 68 if (VDBG) Rlog.d(TAG, "calling handleCdmaStatusReport()"); 69 handleCdmaStatusReport((SmsMessage) o); 70 } else { 71 Rlog.e(TAG, "handleStatusReport() called for object type " + o.getClass().getName()); 72 } 73 } 74 75 /** 76 * Called from parent class to handle status report from {@code CdmaInboundSmsHandler}. 77 * @param sms the CDMA SMS message to process 78 */ 79 void handleCdmaStatusReport(SmsMessage sms) { 80 for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { 81 SmsTracker tracker = deliveryPendingList.get(i); 82 if (tracker.mMessageRef == sms.mMessageRef) { 83 // Found it. Remove from list and broadcast. 84 deliveryPendingList.remove(i); 85 // Update the message status (COMPLETE) 86 tracker.updateSentMessageStatus(mContext, Sms.STATUS_COMPLETE); 87 88 PendingIntent intent = tracker.mDeliveryIntent; 89 Intent fillIn = new Intent(); 90 fillIn.putExtra("pdu", sms.getPdu()); 91 fillIn.putExtra("format", getFormat()); 92 try { 93 intent.send(mContext, Activity.RESULT_OK, fillIn); 94 } catch (CanceledException ex) {} 95 break; // Only expect to see one tracker matching this message. 96 } 97 } 98 } 99 100 /** {@inheritDoc} */ 101 @Override 102 protected void sendData(String destAddr, String scAddr, int destPort, 103 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 104 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 105 scAddr, destAddr, destPort, data, (deliveryIntent != null)); 106 HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu); 107 SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, 108 getFormat()); 109 sendSubmitPdu(tracker); 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 protected void sendText(String destAddr, String scAddr, String text, 115 PendingIntent sentIntent, PendingIntent deliveryIntent) { 116 SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 117 scAddr, destAddr, text, (deliveryIntent != null), null); 118 HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu); 119 SmsTracker tracker = getSmsTracker(map, sentIntent, 120 deliveryIntent, getFormat()); 121 sendSubmitPdu(tracker); 122 } 123 124 /** {@inheritDoc} */ 125 @Override 126 protected GsmAlphabet.TextEncodingDetails calculateLength(CharSequence messageBody, 127 boolean use7bitOnly) { 128 return SmsMessage.calculateLength(messageBody, use7bitOnly); 129 } 130 131 /** {@inheritDoc} */ 132 @Override 133 protected void sendNewSubmitPdu(String destinationAddress, String scAddress, 134 String message, SmsHeader smsHeader, int encoding, 135 PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) { 136 UserData uData = new UserData(); 137 uData.payloadStr = message; 138 uData.userDataHeader = smsHeader; 139 if (encoding == SmsConstants.ENCODING_7BIT) { 140 uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; 141 } else { // assume UTF-16 142 uData.msgEncoding = UserData.ENCODING_UNICODE_16; 143 } 144 uData.msgEncodingSet = true; 145 146 /* By setting the statusReportRequested bit only for the 147 * last message fragment, this will result in only one 148 * callback to the sender when that last fragment delivery 149 * has been acknowledged. */ 150 SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destinationAddress, 151 uData, (deliveryIntent != null) && lastPart); 152 153 HashMap map = getSmsTrackerMap(destinationAddress, scAddress, 154 message, submitPdu); 155 SmsTracker tracker = getSmsTracker(map, sentIntent, 156 deliveryIntent, getFormat()); 157 sendSubmitPdu(tracker); 158 } 159 160 protected void sendSubmitPdu(SmsTracker tracker) { 161 if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false)) { 162 if (tracker.mSentIntent != null) { 163 try { 164 tracker.mSentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE); 165 } catch (CanceledException ex) {} 166 } 167 if (VDBG) { 168 Rlog.d(TAG, "Block SMS in Emergency Callback mode"); 169 } 170 return; 171 } 172 sendRawPdu(tracker); 173 } 174 175 /** {@inheritDoc} */ 176 @Override 177 protected void sendSms(SmsTracker tracker) { 178 HashMap<String, Object> map = tracker.mData; 179 180 // byte[] smsc = (byte[]) map.get("smsc"); // unused for CDMA 181 byte[] pdu = (byte[]) map.get("pdu"); 182 183 Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); 184 185 Rlog.d(TAG, "sendSms: " 186 +" isIms()="+isIms() 187 +" mRetryCount="+tracker.mRetryCount 188 +" mImsRetry="+tracker.mImsRetry 189 +" mMessageRef="+tracker.mMessageRef 190 +" SS=" +mPhone.getServiceState().getState()); 191 192 // sms over cdma is used: 193 // if sms over IMS is not supported AND 194 // this is not a retry case after sms over IMS failed 195 // indicated by mImsRetry > 0 196 if (0 == tracker.mImsRetry && !isIms()) { 197 mCi.sendCdmaSms(pdu, reply); 198 } else { 199 mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply); 200 // increment it here, so in case of SMS_FAIL_RETRY over IMS 201 // next retry will be sent using IMS request again. 202 tracker.mImsRetry++; 203 } 204 } 205 } 206