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