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