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