• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.PhoneConstants;
35 import com.android.internal.telephony.WakeLockStateMachine;
36 import com.android.internal.telephony.cdma.sms.BearerData;
37 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
38 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
39 
40 import java.io.ByteArrayOutputStream;
41 import java.io.DataOutputStream;
42 import java.io.IOException;
43 import java.util.ArrayList;
44 
45 /**
46  * Handle CDMA Service Category Program Data requests and responses.
47  */
48 public final class CdmaServiceCategoryProgramHandler extends WakeLockStateMachine {
49 
50     final CommandsInterface mCi;
51 
52     /**
53      * Create a new CDMA inbound SMS handler.
54      */
CdmaServiceCategoryProgramHandler(Context context, CommandsInterface commandsInterface)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      */
makeScpHandler(Context context, CommandsInterface commandsInterface)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
handleSmsMessage(Message message)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      */
handleServiceCategoryProgramData(SmsMessage sms)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