1/* 2 * Copyright (C) 2013 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.gsm; 18 19import android.app.Activity; 20import android.content.Context; 21import android.os.Message; 22import android.provider.Telephony.Sms.Intents; 23 24import com.android.internal.telephony.CommandsInterface; 25import com.android.internal.telephony.InboundSmsHandler; 26import com.android.internal.telephony.Phone; 27import com.android.internal.telephony.SmsConstants; 28import com.android.internal.telephony.SmsHeader; 29import com.android.internal.telephony.SmsMessageBase; 30import com.android.internal.telephony.SmsStorageMonitor; 31import com.android.internal.telephony.VisualVoicemailSmsFilter; 32import com.android.internal.telephony.uicc.IccRecords; 33import com.android.internal.telephony.uicc.UiccController; 34import com.android.internal.telephony.uicc.UsimServiceTable; 35 36/** 37 * This class broadcasts incoming SMS messages to interested apps after storing them in 38 * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been 39 */ 40public class GsmInboundSmsHandler extends InboundSmsHandler { 41 42 /** Handler for SMS-PP data download messages to UICC. */ 43 private final UsimDataDownloadHandler mDataDownloadHandler; 44 45 /** 46 * Create a new GSM inbound SMS handler. 47 */ 48 private GsmInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor, 49 Phone phone) { 50 super("GsmInboundSmsHandler", context, storageMonitor, phone, 51 GsmCellBroadcastHandler.makeGsmCellBroadcastHandler(context, phone)); 52 phone.mCi.setOnNewGsmSms(getHandler(), EVENT_NEW_SMS, null); 53 mDataDownloadHandler = new UsimDataDownloadHandler(phone.mCi); 54 } 55 56 /** 57 * Unregister for GSM SMS. 58 */ 59 @Override 60 protected void onQuitting() { 61 mPhone.mCi.unSetOnNewGsmSms(getHandler()); 62 mCellBroadcastHandler.dispose(); 63 64 if (DBG) log("unregistered for 3GPP SMS"); 65 super.onQuitting(); // release wakelock 66 } 67 68 /** 69 * Wait for state machine to enter startup state. We can't send any messages until then. 70 */ 71 public static GsmInboundSmsHandler makeInboundSmsHandler(Context context, 72 SmsStorageMonitor storageMonitor, Phone phone) { 73 GsmInboundSmsHandler handler = new GsmInboundSmsHandler(context, storageMonitor, phone); 74 handler.start(); 75 return handler; 76 } 77 78 /** 79 * Return true if this handler is for 3GPP2 messages; false for 3GPP format. 80 * @return false (3GPP) 81 */ 82 @Override 83 protected boolean is3gpp2() { 84 return false; 85 } 86 87 /** 88 * Handle type zero, SMS-PP data download, and 3GPP/CPHS MWI type SMS. Normal SMS messages 89 * are handled by {@link #dispatchNormalMessage} in parent class. 90 * 91 * @param smsb the SmsMessageBase object from the RIL 92 * @return a result code from {@link android.provider.Telephony.Sms.Intents}, 93 * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC 94 */ 95 @Override 96 protected int dispatchMessageRadioSpecific(SmsMessageBase smsb) { 97 SmsMessage sms = (SmsMessage) smsb; 98 99 if (sms.isTypeZero()) { 100 // Some carriers will send visual voicemail SMS as type zero. 101 int destPort = -1; 102 SmsHeader smsHeader = sms.getUserDataHeader(); 103 if (smsHeader != null && smsHeader.portAddrs != null) { 104 // The message was sent to a port. 105 destPort = smsHeader.portAddrs.destPort; 106 } 107 VisualVoicemailSmsFilter 108 .filter(mContext, new byte[][]{sms.getPdu()}, SmsConstants.FORMAT_3GPP, 109 destPort, mPhone.getSubId()); 110 // As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be 111 // Displayed/Stored/Notified. They should only be acknowledged. 112 log("Received short message type 0, Don't display or store it. Send Ack"); 113 return Intents.RESULT_SMS_HANDLED; 114 } 115 116 // Send SMS-PP data download messages to UICC. See 3GPP TS 31.111 section 7.1.1. 117 if (sms.isUsimDataDownload()) { 118 UsimServiceTable ust = mPhone.getUsimServiceTable(); 119 return mDataDownloadHandler.handleUsimDataDownload(ust, sms); 120 } 121 122 boolean handled = false; 123 if (sms.isMWISetMessage()) { 124 updateMessageWaitingIndicator(sms.getNumOfVoicemails()); 125 handled = sms.isMwiDontStore(); 126 if (DBG) log("Received voice mail indicator set SMS shouldStore=" + !handled); 127 } else if (sms.isMWIClearMessage()) { 128 updateMessageWaitingIndicator(0); 129 handled = sms.isMwiDontStore(); 130 if (DBG) log("Received voice mail indicator clear SMS shouldStore=" + !handled); 131 } 132 if (handled) { 133 return Intents.RESULT_SMS_HANDLED; 134 } 135 136 if (!mStorageMonitor.isStorageAvailable() && 137 sms.getMessageClass() != SmsConstants.MessageClass.CLASS_0) { 138 // It's a storable message and there's no storage available. Bail. 139 // (See TS 23.038 for a description of class 0 messages.) 140 return Intents.RESULT_SMS_OUT_OF_MEMORY; 141 } 142 143 return dispatchNormalMessage(smsb); 144 } 145 146 private void updateMessageWaitingIndicator(int voicemailCount) { 147 // range check 148 if (voicemailCount < 0) { 149 voicemailCount = -1; 150 } else if (voicemailCount > 0xff) { 151 // TS 23.040 9.2.3.24.2 152 // "The value 255 shall be taken to mean 255 or greater" 153 voicemailCount = 0xff; 154 } 155 // update voice mail count in Phone 156 mPhone.setVoiceMessageCount(voicemailCount); 157 // store voice mail count in SIM & shared preferences 158 IccRecords records = UiccController.getInstance().getIccRecords( 159 mPhone.getPhoneId(), UiccController.APP_FAM_3GPP); 160 if (records != null) { 161 log("updateMessageWaitingIndicator: updating SIM Records"); 162 records.setVoiceMessageWaiting(1, voicemailCount); 163 } else { 164 log("updateMessageWaitingIndicator: SIM Records not found"); 165 } 166 } 167 168 /** 169 * Send an acknowledge message. 170 * @param success indicates that last message was successfully received. 171 * @param result result code indicating any error 172 * @param response callback message sent when operation completes. 173 */ 174 @Override 175 protected void acknowledgeLastIncomingSms(boolean success, int result, Message response) { 176 mPhone.mCi.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response); 177 } 178 179 /** 180 * Called when the phone changes the default method updates mPhone 181 * mStorageMonitor and mCellBroadcastHandler.updatePhoneObject. 182 * Override if different or other behavior is desired. 183 * 184 * @param phone 185 */ 186 @Override 187 protected void onUpdatePhoneObject(Phone phone) { 188 super.onUpdatePhoneObject(phone); 189 log("onUpdatePhoneObject: dispose of old CellBroadcastHandler and make a new one"); 190 mCellBroadcastHandler.dispose(); 191 mCellBroadcastHandler = GsmCellBroadcastHandler 192 .makeGsmCellBroadcastHandler(mContext, phone); 193 } 194 195 /** 196 * Convert Android result code to 3GPP SMS failure cause. 197 * @param rc the Android SMS intent result value 198 * @return 0 for success, or a 3GPP SMS failure cause value 199 */ 200 private static int resultToCause(int rc) { 201 switch (rc) { 202 case Activity.RESULT_OK: 203 case Intents.RESULT_SMS_HANDLED: 204 // Cause code is ignored on success. 205 return 0; 206 case Intents.RESULT_SMS_OUT_OF_MEMORY: 207 return CommandsInterface.GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED; 208 case Intents.RESULT_SMS_GENERIC_ERROR: 209 default: 210 return CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR; 211 } 212 } 213} 214