Home | History | Annotate | Download | only in cdma
      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.cdma;
     18 
     19 import android.Manifest;
     20 import android.app.Activity;
     21 import android.app.AppOpsManager;
     22 import android.content.BroadcastReceiver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.os.Bundle;
     26 import android.os.Message;
     27 import android.provider.Telephony.Sms.Intents;
     28 import android.telephony.PhoneNumberUtils;
     29 import android.telephony.cdma.CdmaSmsCbProgramData;
     30 import android.telephony.cdma.CdmaSmsCbProgramResults;
     31 
     32 import com.android.internal.telephony.CommandsInterface;
     33 import com.android.internal.telephony.WakeLockStateMachine;
     34 import com.android.internal.telephony.cdma.sms.BearerData;
     35 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
     36 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
     37 
     38 import java.io.ByteArrayOutputStream;
     39 import java.io.DataOutputStream;
     40 import java.io.IOException;
     41 import java.util.ArrayList;
     42 
     43 /**
     44  * Handle CDMA Service Category Program Data requests and responses.
     45  */
     46 public final class CdmaServiceCategoryProgramHandler extends WakeLockStateMachine {
     47 
     48     final CommandsInterface mCi;
     49 
     50     /**
     51      * Create a new CDMA inbound SMS handler.
     52      */
     53     CdmaServiceCategoryProgramHandler(Context context, CommandsInterface commandsInterface) {
     54         super("CdmaServiceCategoryProgramHandler", context, null);
     55         mContext = context;
     56         mCi = commandsInterface;
     57     }
     58 
     59     /**
     60      * Create a new State machine for SCPD requests.
     61      * @param context the context to use
     62      * @param commandsInterface the radio commands interface
     63      * @return the new SCPD handler
     64      */
     65     static CdmaServiceCategoryProgramHandler makeScpHandler(Context context,
     66             CommandsInterface commandsInterface) {
     67         CdmaServiceCategoryProgramHandler handler = new CdmaServiceCategoryProgramHandler(
     68                 context, commandsInterface);
     69         handler.start();
     70         return handler;
     71     }
     72 
     73     /**
     74      * Handle Cell Broadcast messages from {@code CdmaInboundSmsHandler}.
     75      * 3GPP-format Cell Broadcast messages sent from radio are handled in the subclass.
     76      *
     77      * @param message the message to process
     78      * @return true if an ordered broadcast was sent; false on failure
     79      */
     80     @Override
     81     protected boolean handleSmsMessage(Message message) {
     82         if (message.obj instanceof SmsMessage) {
     83             return handleServiceCategoryProgramData((SmsMessage) message.obj);
     84         } else {
     85             loge("handleMessage got object of type: " + message.obj.getClass().getName());
     86             return false;
     87         }
     88     }
     89 
     90 
     91     /**
     92      * Send SCPD request to CellBroadcastReceiver as an ordered broadcast.
     93      * @param sms the CDMA SmsMessage containing the SCPD request
     94      * @return true if an ordered broadcast was sent; false on failure
     95      */
     96     private boolean handleServiceCategoryProgramData(SmsMessage sms) {
     97         ArrayList<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData();
     98         if (programDataList == null) {
     99             loge("handleServiceCategoryProgramData: program data list is null!");
    100             return false;
    101         }
    102 
    103         Intent intent = new Intent(Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION);
    104         intent.putExtra("sender", sms.getOriginatingAddress());
    105         intent.putParcelableArrayListExtra("program_data", programDataList);
    106 
    107         mContext.sendOrderedBroadcast(intent, Manifest.permission.RECEIVE_SMS,
    108                 AppOpsManager.OP_RECEIVE_SMS, mScpResultsReceiver,
    109                 getHandler(), Activity.RESULT_OK, null, null);
    110         return true;
    111     }
    112 
    113     /**
    114      * Broadcast receiver to handle results of ordered broadcast. Sends the SCPD results
    115      * as a reply SMS, then sends a message to state machine to transition to idle.
    116      */
    117     private final BroadcastReceiver mScpResultsReceiver = new BroadcastReceiver() {
    118         @Override
    119         public void onReceive(Context context, Intent intent) {
    120             sendScpResults();
    121             if (DBG) log("mScpResultsReceiver finished");
    122             sendMessage(EVENT_BROADCAST_COMPLETE);
    123         }
    124 
    125         private void sendScpResults() {
    126             int resultCode = getResultCode();
    127             if ((resultCode != Activity.RESULT_OK) && (resultCode != Intents.RESULT_SMS_HANDLED)) {
    128                 loge("SCP results error: result code = " + resultCode);
    129                 return;
    130             }
    131             Bundle extras = getResultExtras(false);
    132             if (extras == null) {
    133                 loge("SCP results error: missing extras");
    134                 return;
    135             }
    136             String sender = extras.getString("sender");
    137             if (sender == null) {
    138                 loge("SCP results error: missing sender extra.");
    139                 return;
    140             }
    141             ArrayList<CdmaSmsCbProgramResults> results
    142                     = extras.getParcelableArrayList("results");
    143             if (results == null) {
    144                 loge("SCP results error: missing results extra.");
    145                 return;
    146             }
    147 
    148             BearerData bData = new BearerData();
    149             bData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
    150             bData.messageId = SmsMessage.getNextMessageId();
    151             bData.serviceCategoryProgramResults = results;
    152             byte[] encodedBearerData = BearerData.encode(bData);
    153 
    154             ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
    155             DataOutputStream dos = new DataOutputStream(baos);
    156             try {
    157                 dos.writeInt(SmsEnvelope.TELESERVICE_SCPT);
    158                 dos.writeInt(0); //servicePresent
    159                 dos.writeInt(0); //serviceCategory
    160                 CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
    161                         PhoneNumberUtils.cdmaCheckAndProcessPlusCodeForSms(sender));
    162                 dos.write(destAddr.digitMode);
    163                 dos.write(destAddr.numberMode);
    164                 dos.write(destAddr.ton); // number_type
    165                 dos.write(destAddr.numberPlan);
    166                 dos.write(destAddr.numberOfDigits);
    167                 dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
    168                 // Subaddress is not supported.
    169                 dos.write(0); //subaddressType
    170                 dos.write(0); //subaddr_odd
    171                 dos.write(0); //subaddr_nbr_of_digits
    172                 dos.write(encodedBearerData.length);
    173                 dos.write(encodedBearerData, 0, encodedBearerData.length);
    174                 // Ignore the RIL response. TODO: implement retry if SMS send fails.
    175                 mCi.sendCdmaSms(baos.toByteArray(), null);
    176             } catch (IOException e) {
    177                 loge("exception creating SCP results PDU", e);
    178             } finally {
    179                 try {
    180                     dos.close();
    181                 } catch (IOException ignored) {
    182                 }
    183             }
    184         }
    185     };
    186 }
    187