Home | History | Annotate | Download | only in gsm
      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 
     17 package com.android.internal.telephony.gsm;
     18 
     19 import android.app.Activity;
     20 import android.content.Context;
     21 import android.os.Message;
     22 import android.provider.Telephony.Sms.Intents;
     23 
     24 import com.android.internal.telephony.CommandsInterface;
     25 import com.android.internal.telephony.InboundSmsHandler;
     26 import com.android.internal.telephony.Phone;
     27 import com.android.internal.telephony.SmsConstants;
     28 import com.android.internal.telephony.SmsHeader;
     29 import com.android.internal.telephony.SmsMessageBase;
     30 import com.android.internal.telephony.SmsStorageMonitor;
     31 import com.android.internal.telephony.VisualVoicemailSmsFilter;
     32 import com.android.internal.telephony.uicc.IccRecords;
     33 import com.android.internal.telephony.uicc.UiccController;
     34 import 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  */
     40 public 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