1/*
2 * Copyright (C) 2008 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;
18
19import android.app.PendingIntent;
20import android.content.Context;
21import android.util.Log;
22
23import com.android.internal.util.HexDump;
24
25import java.util.ArrayList;
26import java.util.List;
27
28import static android.telephony.SmsManager.STATUS_ON_ICC_FREE;
29
30/**
31 * IccSmsInterfaceManager to provide an inter-process communication to
32 * access Sms in Icc.
33 */
34public abstract class IccSmsInterfaceManager extends ISms.Stub {
35    protected PhoneBase mPhone;
36    protected Context mContext;
37    protected SMSDispatcher mDispatcher;
38
39    protected IccSmsInterfaceManager(PhoneBase phone){
40        mPhone = phone;
41        mContext = phone.getContext();
42    }
43
44    protected void enforceReceiveAndSend(String message) {
45        mContext.enforceCallingPermission(
46                "android.permission.RECEIVE_SMS", message);
47        mContext.enforceCallingPermission(
48                "android.permission.SEND_SMS", message);
49    }
50
51    /**
52     * Send a data based SMS to a specific application port.
53     *
54     * @param destAddr the address to send the message to
55     * @param scAddr is the service center address or null to use
56     *  the current default SMSC
57     * @param destPort the port to deliver the message to
58     * @param data the body of the message to send
59     * @param sentIntent if not NULL this <code>PendingIntent</code> is
60     *  broadcast when the message is successfully sent, or failed.
61     *  The result code will be <code>Activity.RESULT_OK<code> for success,
62     *  or one of these errors:<br>
63     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
64     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
65     *  <code>RESULT_ERROR_NULL_PDU</code><br>
66     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
67     *  the extra "errorCode" containing a radio technology specific value,
68     *  generally only useful for troubleshooting.<br>
69     *  The per-application based SMS control checks sentIntent. If sentIntent
70     *  is NULL the caller will be checked against all unknown applications,
71     *  which cause smaller number of SMS to be sent in checking period.
72     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
73     *  broadcast when the message is delivered to the recipient.  The
74     *  raw pdu of the status report is in the extended data ("pdu").
75     */
76    public void sendData(String destAddr, String scAddr, int destPort,
77            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
78        mPhone.getContext().enforceCallingPermission(
79                "android.permission.SEND_SMS",
80                "Sending SMS message");
81        if (Log.isLoggable("SMS", Log.VERBOSE)) {
82            log("sendData: destAddr=" + destAddr + " scAddr=" + scAddr + " destPort=" +
83                destPort + " data='"+ HexDump.toHexString(data)  + "' sentIntent=" +
84                sentIntent + " deliveryIntent=" + deliveryIntent);
85        }
86        mDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent);
87    }
88
89    /**
90     * Send a text based SMS.
91     *
92     * @param destAddr the address to send the message to
93     * @param scAddr is the service center address or null to use
94     *  the current default SMSC
95     * @param text the body of the message to send
96     * @param sentIntent if not NULL this <code>PendingIntent</code> is
97     *  broadcast when the message is successfully sent, or failed.
98     *  The result code will be <code>Activity.RESULT_OK<code> for success,
99     *  or one of these errors:<br>
100     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
101     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
102     *  <code>RESULT_ERROR_NULL_PDU</code><br>
103     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
104     *  the extra "errorCode" containing a radio technology specific value,
105     *  generally only useful for troubleshooting.<br>
106     *  The per-application based SMS control checks sentIntent. If sentIntent
107     *  is NULL the caller will be checked against all unknown applications,
108     *  which cause smaller number of SMS to be sent in checking period.
109     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
110     *  broadcast when the message is delivered to the recipient.  The
111     *  raw pdu of the status report is in the extended data ("pdu").
112     */
113    public void sendText(String destAddr, String scAddr,
114            String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
115        mPhone.getContext().enforceCallingPermission(
116                "android.permission.SEND_SMS",
117                "Sending SMS message");
118        if (Log.isLoggable("SMS", Log.VERBOSE)) {
119            log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +
120                " text='"+ text + "' sentIntent=" +
121                sentIntent + " deliveryIntent=" + deliveryIntent);
122        }
123        mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);
124    }
125
126    /**
127     * Send a multi-part text based SMS.
128     *
129     * @param destAddr the address to send the message to
130     * @param scAddr is the service center address or null to use
131     *   the current default SMSC
132     * @param parts an <code>ArrayList</code> of strings that, in order,
133     *   comprise the original message
134     * @param sentIntents if not null, an <code>ArrayList</code> of
135     *   <code>PendingIntent</code>s (one for each message part) that is
136     *   broadcast when the corresponding message part has been sent.
137     *   The result code will be <code>Activity.RESULT_OK<code> for success,
138     *   or one of these errors:
139     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
140     *   <code>RESULT_ERROR_RADIO_OFF</code>
141     *   <code>RESULT_ERROR_NULL_PDU</code>.
142     *  The per-application based SMS control checks sentIntent. If sentIntent
143     *  is NULL the caller will be checked against all unknown applications,
144     *  which cause smaller number of SMS to be sent in checking period.
145     * @param deliveryIntents if not null, an <code>ArrayList</code> of
146     *   <code>PendingIntent</code>s (one for each message part) that is
147     *   broadcast when the corresponding message part has been delivered
148     *   to the recipient.  The raw pdu of the status report is in the
149     *   extended data ("pdu").
150     */
151    public void sendMultipartText(String destAddr, String scAddr, List<String> parts,
152            List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
153        mPhone.getContext().enforceCallingPermission(
154                "android.permission.SEND_SMS",
155                "Sending SMS message");
156        if (Log.isLoggable("SMS", Log.VERBOSE)) {
157            int i = 0;
158            for (String part : parts) {
159                log("sendMultipartText: destAddr=" + destAddr + ", srAddr=" + scAddr +
160                        ", part[" + (i++) + "]=" + part);
161            }
162        }
163        mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts,
164                (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents);
165    }
166
167    public int getPremiumSmsPermission(String packageName) {
168        return mDispatcher.getPremiumSmsPermission(packageName);
169    }
170
171    public void setPremiumSmsPermission(String packageName, int permission) {
172        mDispatcher.setPremiumSmsPermission(packageName, permission);
173    }
174
175    /**
176     * create SmsRawData lists from all sms record byte[]
177     * Use null to indicate "free" record
178     *
179     * @param messages List of message records from EF_SMS.
180     * @return SmsRawData list of all in-used records
181     */
182    protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) {
183        int count = messages.size();
184        ArrayList<SmsRawData> ret;
185
186        ret = new ArrayList<SmsRawData>(count);
187
188        for (int i = 0; i < count; i++) {
189            byte[] ba = messages.get(i);
190            if (ba[0] == STATUS_ON_ICC_FREE) {
191                ret.add(null);
192            } else {
193                ret.add(new SmsRawData(messages.get(i)));
194            }
195        }
196
197        return ret;
198    }
199
200    /**
201     * Generates an EF_SMS record from status and raw PDU.
202     *
203     * @param status Message status.  See TS 51.011 10.5.3.
204     * @param pdu Raw message PDU.
205     * @return byte array for the record.
206     */
207    protected byte[] makeSmsRecordData(int status, byte[] pdu) {
208        byte[] data = new byte[IccConstants.SMS_RECORD_LENGTH];
209
210        // Status bits for this record.  See TS 51.011 10.5.3
211        data[0] = (byte)(status & 7);
212
213        System.arraycopy(pdu, 0, data, 1, pdu.length);
214
215        // Pad out with 0xFF's.
216        for (int j = pdu.length+1; j < IccConstants.SMS_RECORD_LENGTH; j++) {
217            data[j] = -1;
218        }
219
220        return data;
221    }
222
223    protected abstract void log(String msg);
224
225}
226