CdmaServiceCategoryProgramHandler.java revision d2feaf918ab0c1173d4ada182532e48d0c0d3f77
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; 290d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.cdma.CdmaSmsCbProgramData; 300d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.cdma.CdmaSmsCbProgramResults; 310d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 320d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.CommandsInterface; 330d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.WakeLockStateMachine; 340d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.cdma.sms.BearerData; 350d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.cdma.sms.CdmaSmsAddress; 360d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.cdma.sms.SmsEnvelope; 370d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 380d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.io.ByteArrayOutputStream; 390d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.io.DataOutputStream; 400d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.io.IOException; 410d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.ArrayList; 420d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 430d4bcdf379842af4b6304809156971e926f374f0Jake Hamby/** 440d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Handle CDMA Service Category Program Data requests and responses. 450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 460d4bcdf379842af4b6304809156971e926f374f0Jake Hambypublic final class CdmaServiceCategoryProgramHandler extends WakeLockStateMachine { 470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby final CommandsInterface mCi; 490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Create a new CDMA inbound SMS handler. 520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby CdmaServiceCategoryProgramHandler(Context context, CommandsInterface commandsInterface) { 54d2feaf918ab0c1173d4ada182532e48d0c0d3f77Wink Saville super("CdmaServiceCategoryProgramHandler", context, null); 550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mContext = context; 560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mCi = commandsInterface; 570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Create a new State machine for SCPD requests. 610d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * @param context the context to use 620d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * @param commandsInterface the radio commands interface 630d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * @return the new SCPD handler 640d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby static CdmaServiceCategoryProgramHandler makeScpHandler(Context context, 660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby CommandsInterface commandsInterface) { 670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby CdmaServiceCategoryProgramHandler handler = new CdmaServiceCategoryProgramHandler( 680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby context, commandsInterface); 690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby handler.start(); 700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return handler; 710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Handle Cell Broadcast messages from {@code CdmaInboundSmsHandler}. 750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * 3GPP-format Cell Broadcast messages sent from radio are handled in the subclass. 760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * 770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * @param message the message to process 780d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * @return true if an ordered broadcast was sent; false on failure 790d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 800d4bcdf379842af4b6304809156971e926f374f0Jake Hamby @Override 810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby protected boolean handleSmsMessage(Message message) { 820d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (message.obj instanceof SmsMessage) { 830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return handleServiceCategoryProgramData((SmsMessage) message.obj); 840d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 850d4bcdf379842af4b6304809156971e926f374f0Jake Hamby loge("handleMessage got object of type: " + message.obj.getClass().getName()); 860d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return false; 870d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 880d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 890d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 900d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 910d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 920d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Send SCPD request to CellBroadcastReceiver as an ordered broadcast. 930d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * @param sms the CDMA SmsMessage containing the SCPD request 940d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * @return true if an ordered broadcast was sent; false on failure 950d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 960d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private boolean handleServiceCategoryProgramData(SmsMessage sms) { 970d4bcdf379842af4b6304809156971e926f374f0Jake Hamby ArrayList<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData(); 980d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (programDataList == null) { 990d4bcdf379842af4b6304809156971e926f374f0Jake Hamby loge("handleServiceCategoryProgramData: program data list is null!"); 1000d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return false; 1010d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1020d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1030d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Intent intent = new Intent(Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION); 1040d4bcdf379842af4b6304809156971e926f374f0Jake Hamby intent.putExtra("sender", sms.getOriginatingAddress()); 1050d4bcdf379842af4b6304809156971e926f374f0Jake Hamby intent.putParcelableArrayListExtra("program_data", programDataList); 1060d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1070d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mContext.sendOrderedBroadcast(intent, Manifest.permission.RECEIVE_SMS, 1080d4bcdf379842af4b6304809156971e926f374f0Jake Hamby AppOpsManager.OP_RECEIVE_SMS, mScpResultsReceiver, 1090d4bcdf379842af4b6304809156971e926f374f0Jake Hamby getHandler(), Activity.RESULT_OK, null, null); 1100d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return true; 1110d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1120d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1130d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 1140d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Broadcast receiver to handle results of ordered broadcast. Sends the SCPD results 1150d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * as a reply SMS, then sends a message to state machine to transition to idle. 1160d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 1170d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private final BroadcastReceiver mScpResultsReceiver = new BroadcastReceiver() { 1180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby @Override 1190d4bcdf379842af4b6304809156971e926f374f0Jake Hamby public void onReceive(Context context, Intent intent) { 1200d4bcdf379842af4b6304809156971e926f374f0Jake Hamby sendScpResults(); 1210d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (DBG) log("mScpResultsReceiver finished"); 1220d4bcdf379842af4b6304809156971e926f374f0Jake Hamby sendMessage(EVENT_BROADCAST_COMPLETE); 1230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private void sendScpResults() { 1260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby int resultCode = getResultCode(); 1270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if ((resultCode != Activity.RESULT_OK) && (resultCode != Intents.RESULT_SMS_HANDLED)) { 1280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby loge("SCP results error: result code = " + resultCode); 1290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return; 1300d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1310d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Bundle extras = getResultExtras(false); 1320d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (extras == null) { 1330d4bcdf379842af4b6304809156971e926f374f0Jake Hamby loge("SCP results error: missing extras"); 1340d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return; 1350d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1360d4bcdf379842af4b6304809156971e926f374f0Jake Hamby String sender = extras.getString("sender"); 1370d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (sender == null) { 1380d4bcdf379842af4b6304809156971e926f374f0Jake Hamby loge("SCP results error: missing sender extra."); 1390d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return; 1400d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1410d4bcdf379842af4b6304809156971e926f374f0Jake Hamby ArrayList<CdmaSmsCbProgramResults> results 1420d4bcdf379842af4b6304809156971e926f374f0Jake Hamby = extras.getParcelableArrayList("results"); 1430d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (results == null) { 1440d4bcdf379842af4b6304809156971e926f374f0Jake Hamby loge("SCP results error: missing results extra."); 1450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return; 1460d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby BearerData bData = new BearerData(); 1490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby bData.messageType = BearerData.MESSAGE_TYPE_SUBMIT; 1500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby bData.messageId = SmsMessage.getNextMessageId(); 1510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby bData.serviceCategoryProgramResults = results; 1520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby byte[] encodedBearerData = BearerData.encode(bData); 1530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby ByteArrayOutputStream baos = new ByteArrayOutputStream(100); 1550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby DataOutputStream dos = new DataOutputStream(baos); 1560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby try { 1570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.writeInt(SmsEnvelope.TELESERVICE_SCPT); 1580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.writeInt(0); //servicePresent 1590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.writeInt(0); //serviceCategory 1600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby CdmaSmsAddress destAddr = CdmaSmsAddress.parse( 1610d4bcdf379842af4b6304809156971e926f374f0Jake Hamby PhoneNumberUtils.cdmaCheckAndProcessPlusCode(sender)); 1620d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(destAddr.digitMode); 1630d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(destAddr.numberMode); 1640d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(destAddr.ton); // number_type 1650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(destAddr.numberPlan); 1660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(destAddr.numberOfDigits); 1670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits 1680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // Subaddress is not supported. 1690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(0); //subaddressType 1700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(0); //subaddr_odd 1710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(0); //subaddr_nbr_of_digits 1720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(encodedBearerData.length); 1730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.write(encodedBearerData, 0, encodedBearerData.length); 1740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // Ignore the RIL response. TODO: implement retry if SMS send fails. 1750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mCi.sendCdmaSms(baos.toByteArray(), null); 1760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } catch (IOException e) { 1770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby loge("exception creating SCP results PDU", e); 1780d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } finally { 1790d4bcdf379842af4b6304809156971e926f374f0Jake Hamby try { 1800d4bcdf379842af4b6304809156971e926f374f0Jake Hamby dos.close(); 1810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } catch (IOException ignored) { 1820d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1840d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1850d4bcdf379842af4b6304809156971e926f374f0Jake Hamby }; 1860d4bcdf379842af4b6304809156971e926f374f0Jake Hamby} 187