1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
4 * Not a Contribution.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19package com.android.internal.telephony;
20
21import android.annotation.Nullable;
22import android.app.ActivityThread;
23import android.app.PendingIntent;
24import android.content.Context;
25import android.net.Uri;
26import android.os.Binder;
27import android.os.RemoteException;
28import android.os.ServiceManager;
29import android.provider.Telephony.Sms.Intents;
30import android.telephony.Rlog;
31import android.telephony.SmsManager;
32import android.telephony.SubscriptionInfo;
33import android.telephony.SubscriptionManager;
34import android.telephony.TelephonyManager;
35
36import java.util.List;
37
38/**
39 * UiccSmsController to provide an inter-process communication to
40 * access Sms in Icc.
41 */
42public class UiccSmsController extends ISms.Stub {
43    static final String LOG_TAG = "RIL_UiccSmsController";
44
45    protected Phone[] mPhone;
46
47    protected UiccSmsController(Phone[] phone){
48        mPhone = phone;
49
50        if (ServiceManager.getService("isms") == null) {
51            ServiceManager.addService("isms", this);
52        }
53    }
54
55    @Override
56    public boolean
57    updateMessageOnIccEfForSubscriber(int subId, String callingPackage, int index, int status,
58                byte[] pdu) throws android.os.RemoteException {
59        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
60        if (iccSmsIntMgr != null) {
61            return iccSmsIntMgr.updateMessageOnIccEf(callingPackage, index, status, pdu);
62        } else {
63            Rlog.e(LOG_TAG,"updateMessageOnIccEfForSubscriber iccSmsIntMgr is null" +
64                          " for Subscription: " + subId);
65            return false;
66        }
67    }
68
69    @Override
70    public boolean copyMessageToIccEfForSubscriber(int subId, String callingPackage, int status,
71            byte[] pdu, byte[] smsc) throws android.os.RemoteException {
72        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
73        if (iccSmsIntMgr != null) {
74            return iccSmsIntMgr.copyMessageToIccEf(callingPackage, status, pdu, smsc);
75        } else {
76            Rlog.e(LOG_TAG,"copyMessageToIccEfForSubscriber iccSmsIntMgr is null" +
77                          " for Subscription: " + subId);
78            return false;
79        }
80    }
81
82    @Override
83    public List<SmsRawData> getAllMessagesFromIccEfForSubscriber(int subId, String callingPackage)
84                throws android.os.RemoteException {
85        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
86        if (iccSmsIntMgr != null) {
87            return iccSmsIntMgr.getAllMessagesFromIccEf(callingPackage);
88        } else {
89            Rlog.e(LOG_TAG,"getAllMessagesFromIccEfForSubscriber iccSmsIntMgr is" +
90                          " null for Subscription: " + subId);
91            return null;
92        }
93    }
94
95    @Override
96    public void sendDataForSubscriber(int subId, String callingPackage, String destAddr,
97            String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
98            PendingIntent deliveryIntent) {
99        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
100        if (iccSmsIntMgr != null) {
101            iccSmsIntMgr.sendData(callingPackage, destAddr, scAddr, destPort, data,
102                    sentIntent, deliveryIntent);
103        } else {
104            Rlog.e(LOG_TAG,"sendDataForSubscriber iccSmsIntMgr is null for" +
105                          " Subscription: " + subId);
106            // TODO: Use a more specific error code to replace RESULT_ERROR_GENERIC_FAILURE.
107            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
108        }
109    }
110
111    public void sendDataForSubscriberWithSelfPermissions(int subId, String callingPackage,
112            String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
113            PendingIntent deliveryIntent) {
114        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
115        if (iccSmsIntMgr != null) {
116            iccSmsIntMgr.sendDataWithSelfPermissions(callingPackage, destAddr, scAddr, destPort, data,
117                    sentIntent, deliveryIntent);
118        } else {
119            Rlog.e(LOG_TAG,"sendText iccSmsIntMgr is null for" +
120                          " Subscription: " + subId);
121        }
122    }
123
124    public void sendText(String callingPackage, String destAddr, String scAddr,
125            String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
126        sendTextForSubscriber(getPreferredSmsSubscription(), callingPackage, destAddr, scAddr,
127            text, sentIntent, deliveryIntent, true /* persistMessageForNonDefaultSmsApp*/);
128    }
129
130    @Override
131    public void sendTextForSubscriber(int subId, String callingPackage, String destAddr,
132            String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
133            boolean persistMessageForNonDefaultSmsApp) {
134        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
135        if (iccSmsIntMgr != null) {
136            iccSmsIntMgr.sendText(callingPackage, destAddr, scAddr, text, sentIntent,
137                    deliveryIntent, persistMessageForNonDefaultSmsApp);
138        } else {
139            Rlog.e(LOG_TAG,"sendTextForSubscriber iccSmsIntMgr is null for" +
140                          " Subscription: " + subId);
141            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
142        }
143    }
144
145    public void sendTextForSubscriberWithSelfPermissions(int subId, String callingPackage,
146            String destAddr, String scAddr, String text, PendingIntent sentIntent,
147            PendingIntent deliveryIntent) {
148        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
149        if (iccSmsIntMgr != null) {
150            iccSmsIntMgr.sendTextWithSelfPermissions(callingPackage, destAddr, scAddr, text,
151                    sentIntent, deliveryIntent);
152        } else {
153            Rlog.e(LOG_TAG,"sendText iccSmsIntMgr is null for" +
154                          " Subscription: " + subId);
155        }
156    }
157
158    public void sendMultipartText(String callingPackage, String destAddr, String scAddr,
159            List<String> parts, List<PendingIntent> sentIntents,
160            List<PendingIntent> deliveryIntents) throws android.os.RemoteException {
161         sendMultipartTextForSubscriber(getPreferredSmsSubscription(), callingPackage, destAddr,
162                 scAddr, parts, sentIntents, deliveryIntents,
163                 true /* persistMessageForNonDefaultSmsApp */);
164    }
165
166    @Override
167    public void sendMultipartTextForSubscriber(int subId, String callingPackage, String destAddr,
168            String scAddr, List<String> parts, List<PendingIntent> sentIntents,
169            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp)
170            throws android.os.RemoteException {
171        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
172        if (iccSmsIntMgr != null ) {
173            iccSmsIntMgr.sendMultipartText(callingPackage, destAddr, scAddr, parts, sentIntents,
174                    deliveryIntents, persistMessageForNonDefaultSmsApp);
175        } else {
176            Rlog.e(LOG_TAG,"sendMultipartTextForSubscriber iccSmsIntMgr is null for" +
177                          " Subscription: " + subId);
178            sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
179        }
180    }
181
182    @Override
183    public boolean enableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType)
184                throws android.os.RemoteException {
185        return enableCellBroadcastRangeForSubscriber(subId, messageIdentifier, messageIdentifier,
186                ranType);
187    }
188
189    @Override
190    public boolean enableCellBroadcastRangeForSubscriber(int subId, int startMessageId,
191            int endMessageId, int ranType) throws android.os.RemoteException {
192        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
193        if (iccSmsIntMgr != null ) {
194            return iccSmsIntMgr.enableCellBroadcastRange(startMessageId, endMessageId, ranType);
195        } else {
196            Rlog.e(LOG_TAG,"enableCellBroadcastRangeForSubscriber iccSmsIntMgr is null for" +
197                          " Subscription: " + subId);
198        }
199        return false;
200    }
201
202    @Override
203    public boolean disableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType)
204                throws android.os.RemoteException {
205        return disableCellBroadcastRangeForSubscriber(subId, messageIdentifier, messageIdentifier,
206                ranType);
207    }
208
209    @Override
210    public boolean disableCellBroadcastRangeForSubscriber(int subId, int startMessageId,
211            int endMessageId, int ranType) throws android.os.RemoteException {
212        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
213        if (iccSmsIntMgr != null ) {
214            return iccSmsIntMgr.disableCellBroadcastRange(startMessageId, endMessageId, ranType);
215        } else {
216            Rlog.e(LOG_TAG,"disableCellBroadcastRangeForSubscriber iccSmsIntMgr is null for" +
217                          " Subscription:"+subId);
218        }
219       return false;
220    }
221
222    @Override
223    public int getPremiumSmsPermission(String packageName) {
224        return getPremiumSmsPermissionForSubscriber(getPreferredSmsSubscription(), packageName);
225    }
226
227    @Override
228    public int getPremiumSmsPermissionForSubscriber(int subId, String packageName) {
229        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
230        if (iccSmsIntMgr != null ) {
231            return iccSmsIntMgr.getPremiumSmsPermission(packageName);
232        } else {
233            Rlog.e(LOG_TAG, "getPremiumSmsPermissionForSubscriber iccSmsIntMgr is null");
234        }
235        //TODO Rakesh
236        return 0;
237    }
238
239    @Override
240    public void setPremiumSmsPermission(String packageName, int permission) {
241         setPremiumSmsPermissionForSubscriber(getPreferredSmsSubscription(), packageName, permission);
242    }
243
244    @Override
245    public void setPremiumSmsPermissionForSubscriber(int subId, String packageName, int permission) {
246        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
247        if (iccSmsIntMgr != null ) {
248            iccSmsIntMgr.setPremiumSmsPermission(packageName, permission);
249        } else {
250            Rlog.e(LOG_TAG, "setPremiumSmsPermissionForSubscriber iccSmsIntMgr is null");
251        }
252    }
253
254    @Override
255    public boolean isImsSmsSupportedForSubscriber(int subId) {
256        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
257        if (iccSmsIntMgr != null ) {
258            return iccSmsIntMgr.isImsSmsSupported();
259        } else {
260            Rlog.e(LOG_TAG, "isImsSmsSupportedForSubscriber iccSmsIntMgr is null");
261        }
262        return false;
263    }
264
265    @Override
266    public boolean isSmsSimPickActivityNeeded(int subId) {
267        final Context context = ActivityThread.currentApplication().getApplicationContext();
268        TelephonyManager telephonyManager =
269                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
270        List<SubscriptionInfo> subInfoList;
271        final long identity = Binder.clearCallingIdentity();
272        try {
273            subInfoList = SubscriptionManager.from(context).getActiveSubscriptionInfoList();
274        } finally {
275            Binder.restoreCallingIdentity(identity);
276        }
277
278        if (subInfoList != null) {
279            final int subInfoLength = subInfoList.size();
280
281            for (int i = 0; i < subInfoLength; ++i) {
282                final SubscriptionInfo sir = subInfoList.get(i);
283                if (sir != null && sir.getSubscriptionId() == subId) {
284                    // The subscription id is valid, sms sim pick activity not needed
285                    return false;
286                }
287            }
288
289            // If reached here and multiple SIMs and subs present, sms sim pick activity is needed
290            if (subInfoLength > 0 && telephonyManager.getSimCount() > 1) {
291                return true;
292            }
293        }
294
295        return false;
296    }
297
298    @Override
299    public String getImsSmsFormatForSubscriber(int subId) {
300        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
301        if (iccSmsIntMgr != null ) {
302            return iccSmsIntMgr.getImsSmsFormat();
303        } else {
304            Rlog.e(LOG_TAG, "getImsSmsFormatForSubscriber iccSmsIntMgr is null");
305        }
306        return null;
307    }
308
309    @Override
310    public void injectSmsPduForSubscriber(
311            int subId, byte[] pdu, String format, PendingIntent receivedIntent) {
312        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
313        if (iccSmsIntMgr != null) {
314            iccSmsIntMgr.injectSmsPdu(pdu, format, receivedIntent);
315        } else {
316            Rlog.e(LOG_TAG, "injectSmsPduForSubscriber iccSmsIntMgr is null");
317            // RESULT_SMS_GENERIC_ERROR is documented for injectSmsPdu
318            sendErrorInPendingIntent(receivedIntent, Intents.RESULT_SMS_GENERIC_ERROR);
319        }
320    }
321
322    /**
323     * get sms interface manager object based on subscription.
324     **/
325    private @Nullable IccSmsInterfaceManager getIccSmsInterfaceManager(int subId) {
326        if (!isActiveSubId(subId)) {
327            Rlog.e(LOG_TAG, "Subscription " + subId + " is inactive.");
328            return null;
329        }
330
331        int phoneId = SubscriptionController.getInstance().getPhoneId(subId) ;
332        //Fixme: for multi-subscription case
333        if (!SubscriptionManager.isValidPhoneId(phoneId)
334                || phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
335            phoneId = 0;
336        }
337
338        try {
339            return (IccSmsInterfaceManager)
340                ((Phone)mPhone[(int)phoneId]).getIccSmsInterfaceManager();
341        } catch (NullPointerException e) {
342            Rlog.e(LOG_TAG, "Exception is :"+e.toString()+" For subscription :"+subId );
343            e.printStackTrace();
344            return null;
345        } catch (ArrayIndexOutOfBoundsException e) {
346            Rlog.e(LOG_TAG, "Exception is :"+e.toString()+" For subscription :"+subId );
347            e.printStackTrace();
348            return null;
349        }
350    }
351
352    /**
353       Gets User preferred SMS subscription */
354    @Override
355    public int getPreferredSmsSubscription() {
356        return SubscriptionController.getInstance().getDefaultSmsSubId();
357    }
358
359    /**
360     * Get SMS prompt property,  enabled or not
361     **/
362    @Override
363    public boolean isSMSPromptEnabled() {
364        return PhoneFactory.isSMSPromptEnabled();
365    }
366
367    @Override
368    public void sendStoredText(int subId, String callingPkg, Uri messageUri, String scAddress,
369            PendingIntent sentIntent, PendingIntent deliveryIntent) throws RemoteException {
370        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
371        if (iccSmsIntMgr != null) {
372            iccSmsIntMgr.sendStoredText(callingPkg, messageUri, scAddress, sentIntent,
373                    deliveryIntent);
374        } else {
375            Rlog.e(LOG_TAG,"sendStoredText iccSmsIntMgr is null for subscription: " + subId);
376            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
377        }
378    }
379
380    @Override
381    public void sendStoredMultipartText(int subId, String callingPkg, Uri messageUri,
382            String scAddress, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)
383            throws RemoteException {
384        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
385        if (iccSmsIntMgr != null ) {
386            iccSmsIntMgr.sendStoredMultipartText(callingPkg, messageUri, scAddress, sentIntents,
387                    deliveryIntents);
388        } else {
389            Rlog.e(LOG_TAG,"sendStoredMultipartText iccSmsIntMgr is null for subscription: "
390                    + subId);
391            sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
392        }
393    }
394
395    /*
396     * @return true if the subId is active.
397     */
398    private boolean isActiveSubId(int subId) {
399        return SubscriptionController.getInstance().isActiveSubId(subId);
400    }
401
402    private void sendErrorInPendingIntent(@Nullable PendingIntent intent, int errorCode) {
403        if (intent != null) {
404            try {
405                intent.send(errorCode);
406            } catch (PendingIntent.CanceledException ex) {
407            }
408        }
409    }
410
411    private void sendErrorInPendingIntents(List<PendingIntent> intents, int errorCode) {
412        for (PendingIntent intent : intents) {
413            sendErrorInPendingIntent(intent, errorCode);
414        }
415    }
416}
417