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.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 Phone 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, Phone 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 private 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 Phone 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 } 155 156 /** 157 * Send an acknowledge message. 158 * @param success indicates that last message was successfully received. 159 * @param result result code indicating any error 160 * @param response callback message sent when operation completes. 161 */ 162 @Override 163 protected void acknowledgeLastIncomingSms(boolean success, int result, Message response) { 164 mPhone.mCi.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response); 165 } 166 167 /** 168 * Called when the phone changes the default method updates mPhone 169 * mStorageMonitor and mCellBroadcastHandler.updatePhoneObject. 170 * Override if different or other behavior is desired. 171 * 172 * @param phone 173 */ 174 @Override 175 protected void onUpdatePhoneObject(Phone phone) { 176 super.onUpdatePhoneObject(phone); 177 log("onUpdatePhoneObject: dispose of old CellBroadcastHandler and make a new one"); 178 mCellBroadcastHandler.dispose(); 179 mCellBroadcastHandler = GsmCellBroadcastHandler 180 .makeGsmCellBroadcastHandler(mContext, phone); 181 } 182 183 /** 184 * Convert Android result code to 3GPP SMS failure cause. 185 * @param rc the Android SMS intent result value 186 * @return 0 for success, or a 3GPP SMS failure cause value 187 */ 188 private static int resultToCause(int rc) { 189 switch (rc) { 190 case Activity.RESULT_OK: 191 case Intents.RESULT_SMS_HANDLED: 192 // Cause code is ignored on success. 193 return 0; 194 case Intents.RESULT_SMS_OUT_OF_MEMORY: 195 return CommandsInterface.GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED; 196 case Intents.RESULT_SMS_GENERIC_ERROR: 197 default: 198 return CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR; 199 } 200 } 201} 202