10d4bcdf379842af4b6304809156971e926f374f0Jake Hamby/*
20d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Copyright (C) 2013 The Android Open Source Project
30d4bcdf379842af4b6304809156971e926f374f0Jake Hamby *
40d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Licensed under the Apache License, Version 2.0 (the "License");
50d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * you may not use this file except in compliance with the License.
60d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * You may obtain a copy of the License at
70d4bcdf379842af4b6304809156971e926f374f0Jake Hamby *
80d4bcdf379842af4b6304809156971e926f374f0Jake Hamby *      http://www.apache.org/licenses/LICENSE-2.0
90d4bcdf379842af4b6304809156971e926f374f0Jake Hamby *
100d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Unless required by applicable law or agreed to in writing, software
110d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * distributed under the License is distributed on an "AS IS" BASIS,
120d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * See the License for the specific language governing permissions and
140d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * limitations under the License.
150d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */
160d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
170d4bcdf379842af4b6304809156971e926f374f0Jake Hambypackage com.android.internal.telephony.cdma;
180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
190d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.Manifest;
200d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.app.Activity;
210d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.app.AppOpsManager;
220d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.content.BroadcastReceiver;
230d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.content.Context;
240d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.content.Intent;
250d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.os.Bundle;
260d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.os.Message;
270d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.provider.Telephony.Sms.Intents;
280d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.PhoneNumberUtils;
29a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport android.telephony.SubscriptionManager;
300d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.cdma.CdmaSmsCbProgramData;
310d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.cdma.CdmaSmsCbProgramResults;
320d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
330d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.CommandsInterface;
34a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.PhoneConstants;
350d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.WakeLockStateMachine;
360d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.cdma.sms.BearerData;
370d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
380d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.cdma.sms.SmsEnvelope;
390d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
400d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.io.ByteArrayOutputStream;
410d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.io.DataOutputStream;
420d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.io.IOException;
430d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.ArrayList;
440d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby/**
460d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Handle CDMA Service Category Program Data requests and responses.
470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */
480d4bcdf379842af4b6304809156971e926f374f0Jake Hambypublic final class CdmaServiceCategoryProgramHandler extends WakeLockStateMachine {
490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    final CommandsInterface mCi;
510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Create a new CDMA inbound SMS handler.
540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    CdmaServiceCategoryProgramHandler(Context context, CommandsInterface commandsInterface) {
56d2feaf918ab0c1173d4ada182532e48d0c0d3f77Wink Saville        super("CdmaServiceCategoryProgramHandler", context, null);
570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        mContext = context;
580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        mCi = commandsInterface;
590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
610d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
620d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Create a new State machine for SCPD requests.
630d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param context the context to use
640d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param commandsInterface the radio commands interface
650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @return the new SCPD handler
660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    static CdmaServiceCategoryProgramHandler makeScpHandler(Context context,
680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            CommandsInterface commandsInterface) {
690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        CdmaServiceCategoryProgramHandler handler = new CdmaServiceCategoryProgramHandler(
700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                context, commandsInterface);
710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        handler.start();
720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        return handler;
730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Handle Cell Broadcast messages from {@code CdmaInboundSmsHandler}.
770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * 3GPP-format Cell Broadcast messages sent from radio are handled in the subclass.
780d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     *
790d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param message the message to process
800d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @return true if an ordered broadcast was sent; false on failure
810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
820d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    @Override
830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected boolean handleSmsMessage(Message message) {
840d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        if (message.obj instanceof SmsMessage) {
850d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            return handleServiceCategoryProgramData((SmsMessage) message.obj);
860d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        } else {
870d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            loge("handleMessage got object of type: " + message.obj.getClass().getName());
880d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            return false;
890d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
900d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
910d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
920d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
930d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
940d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Send SCPD request to CellBroadcastReceiver as an ordered broadcast.
950d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param sms the CDMA SmsMessage containing the SCPD request
960d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @return true if an ordered broadcast was sent; false on failure
970d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
980d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    private boolean handleServiceCategoryProgramData(SmsMessage sms) {
990d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        ArrayList<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData();
1000d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        if (programDataList == null) {
1010d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            loge("handleServiceCategoryProgramData: program data list is null!");
1020d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            return false;
1030d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
1040d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1050d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        Intent intent = new Intent(Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION);
1060d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        intent.putExtra("sender", sms.getOriginatingAddress());
1070d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        intent.putParcelableArrayListExtra("program_data", programDataList);
108a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
1090d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        mContext.sendOrderedBroadcast(intent, Manifest.permission.RECEIVE_SMS,
1100d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                AppOpsManager.OP_RECEIVE_SMS, mScpResultsReceiver,
1110d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                getHandler(), Activity.RESULT_OK, null, null);
1120d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        return true;
1130d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
1140d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1150d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
1160d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Broadcast receiver to handle results of ordered broadcast. Sends the SCPD results
1170d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * as a reply SMS, then sends a message to state machine to transition to idle.
1180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
1190d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    private final BroadcastReceiver mScpResultsReceiver = new BroadcastReceiver() {
1200d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        @Override
1210d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        public void onReceive(Context context, Intent intent) {
1220d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            sendScpResults();
1230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            if (DBG) log("mScpResultsReceiver finished");
1240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            sendMessage(EVENT_BROADCAST_COMPLETE);
1250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
1260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        private void sendScpResults() {
1280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            int resultCode = getResultCode();
1290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            if ((resultCode != Activity.RESULT_OK) && (resultCode != Intents.RESULT_SMS_HANDLED)) {
1300d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                loge("SCP results error: result code = " + resultCode);
1310d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                return;
1320d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            }
1330d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            Bundle extras = getResultExtras(false);
1340d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            if (extras == null) {
1350d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                loge("SCP results error: missing extras");
1360d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                return;
1370d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            }
1380d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            String sender = extras.getString("sender");
1390d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            if (sender == null) {
1400d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                loge("SCP results error: missing sender extra.");
1410d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                return;
1420d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            }
1430d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            ArrayList<CdmaSmsCbProgramResults> results
1440d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    = extras.getParcelableArrayList("results");
1450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            if (results == null) {
1460d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                loge("SCP results error: missing results extra.");
1470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                return;
1480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            }
1490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            BearerData bData = new BearerData();
1510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            bData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
1520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            bData.messageId = SmsMessage.getNextMessageId();
1530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            bData.serviceCategoryProgramResults = results;
1540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            byte[] encodedBearerData = BearerData.encode(bData);
1550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
1570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            DataOutputStream dos = new DataOutputStream(baos);
1580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            try {
1590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.writeInt(SmsEnvelope.TELESERVICE_SCPT);
1600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.writeInt(0); //servicePresent
1610d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.writeInt(0); //serviceCategory
1620d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
1638409d93cf9f3ed23db12f24b4f49063ea416b30bJake Hamby                        PhoneNumberUtils.cdmaCheckAndProcessPlusCodeForSms(sender));
1640d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(destAddr.digitMode);
1650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(destAddr.numberMode);
1660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(destAddr.ton); // number_type
1670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(destAddr.numberPlan);
1680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(destAddr.numberOfDigits);
1690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
1700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                // Subaddress is not supported.
1710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(0); //subaddressType
1720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(0); //subaddr_odd
1730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(0); //subaddr_nbr_of_digits
1740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(encodedBearerData.length);
1750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                dos.write(encodedBearerData, 0, encodedBearerData.length);
1760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                // Ignore the RIL response. TODO: implement retry if SMS send fails.
1770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                mCi.sendCdmaSms(baos.toByteArray(), null);
1780d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            } catch (IOException e) {
1790d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                loge("exception creating SCP results PDU", e);
1800d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            } finally {
1810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                try {
1820d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    dos.close();
1830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                } catch (IOException ignored) {
1840d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                }
1850d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            }
1860d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
1870d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    };
1880d4bcdf379842af4b6304809156971e926f374f0Jake Hamby}
189