PhoneInterfaceManager.java revision fee69345c86d13b46e9e1d1e36178ebef17538ee
1/*
2 * Copyright (C) 2006 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.phone;
18
19import android.app.ActivityManager;
20import android.app.AppOpsManager;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.SharedPreferences;
25import android.content.pm.PackageManager;
26import android.net.Uri;
27import android.os.AsyncResult;
28import android.os.Binder;
29import android.os.Bundle;
30import android.os.Handler;
31import android.os.Looper;
32import android.os.Message;
33import android.os.Process;
34import android.os.ServiceManager;
35import android.os.UserHandle;
36import android.os.UserManager;
37import android.preference.PreferenceManager;
38import android.provider.Settings;
39import android.telecom.PhoneAccount;
40import android.telecom.TelecomManager;
41import android.telephony.CarrierConfigManager;
42import android.telephony.CellInfo;
43import android.telephony.IccOpenLogicalChannelResponse;
44import android.telephony.NeighboringCellInfo;
45import android.telephony.RadioAccessFamily;
46import android.telephony.ServiceState;
47import android.telephony.SubscriptionInfo;
48import android.telephony.SubscriptionManager;
49import android.telephony.TelephonyManager;
50import android.telephony.ModemActivityInfo;
51import android.text.TextUtils;
52import android.util.ArrayMap;
53import android.util.ArraySet;
54import android.util.Log;
55import android.util.Pair;
56import android.util.Slog;
57
58import com.android.ims.ImsManager;
59import com.android.internal.telephony.CallManager;
60import com.android.internal.telephony.CellNetworkScanResult;
61import com.android.internal.telephony.CommandException;
62import com.android.internal.telephony.DefaultPhoneNotifier;
63import com.android.internal.telephony.ITelephony;
64import com.android.internal.telephony.IccCard;
65import com.android.internal.telephony.MccTable;
66import com.android.internal.telephony.OperatorInfo;
67import com.android.internal.telephony.Phone;
68import com.android.internal.telephony.PhoneFactory;
69import com.android.internal.telephony.ProxyController;
70import com.android.internal.telephony.PhoneConstants;
71import com.android.internal.telephony.RILConstants;
72import com.android.internal.telephony.SubscriptionController;
73import com.android.internal.telephony.uicc.IccIoResult;
74import com.android.internal.telephony.uicc.IccUtils;
75import com.android.internal.telephony.uicc.UiccCard;
76import com.android.internal.telephony.uicc.UiccController;
77import com.android.internal.util.HexDump;
78
79import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
80
81import java.util.ArrayList;
82import java.util.Arrays;
83import java.util.HashMap;
84import java.util.Iterator;
85import java.util.List;
86import java.util.Locale;
87import java.util.Map;
88import java.util.Objects;
89
90/**
91 * Implementation of the ITelephony interface.
92 */
93public class PhoneInterfaceManager extends ITelephony.Stub {
94    private static final String LOG_TAG = "PhoneInterfaceManager";
95    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
96    private static final boolean DBG_LOC = false;
97    private static final boolean DBG_MERGE = false;
98
99    // Message codes used with mMainThreadHandler
100    private static final int CMD_HANDLE_PIN_MMI = 1;
101    private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
102    private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
103    private static final int CMD_ANSWER_RINGING_CALL = 4;
104    private static final int CMD_END_CALL = 5;  // not used yet
105    private static final int CMD_TRANSMIT_APDU_LOGICAL_CHANNEL = 7;
106    private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 8;
107    private static final int CMD_OPEN_CHANNEL = 9;
108    private static final int EVENT_OPEN_CHANNEL_DONE = 10;
109    private static final int CMD_CLOSE_CHANNEL = 11;
110    private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
111    private static final int CMD_NV_READ_ITEM = 13;
112    private static final int EVENT_NV_READ_ITEM_DONE = 14;
113    private static final int CMD_NV_WRITE_ITEM = 15;
114    private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
115    private static final int CMD_NV_WRITE_CDMA_PRL = 17;
116    private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
117    private static final int CMD_NV_RESET_CONFIG = 19;
118    private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
119    private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
120    private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
121    private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
122    private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
123    private static final int CMD_SEND_ENVELOPE = 25;
124    private static final int EVENT_SEND_ENVELOPE_DONE = 26;
125    private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 27;
126    private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 28;
127    private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 29;
128    private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 30;
129    private static final int CMD_EXCHANGE_SIM_IO = 31;
130    private static final int EVENT_EXCHANGE_SIM_IO_DONE = 32;
131    private static final int CMD_SET_VOICEMAIL_NUMBER = 33;
132    private static final int EVENT_SET_VOICEMAIL_NUMBER_DONE = 34;
133    private static final int CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC = 35;
134    private static final int EVENT_SET_NETWORK_SELECTION_MODE_AUTOMATIC_DONE = 36;
135    private static final int CMD_GET_MODEM_ACTIVITY_INFO = 37;
136    private static final int EVENT_GET_MODEM_ACTIVITY_INFO_DONE = 38;
137    private static final int CMD_PERFORM_NETWORK_SCAN = 39;
138    private static final int EVENT_PERFORM_NETWORK_SCAN_DONE = 40;
139    private static final int CMD_SET_NETWORK_SELECTION_MODE_MANUAL = 41;
140    private static final int EVENT_SET_NETWORK_SELECTION_MODE_MANUAL_DONE = 42;
141
142    /** The singleton instance. */
143    private static PhoneInterfaceManager sInstance;
144
145    private PhoneGlobals mApp;
146    private Phone mPhone;
147    private CallManager mCM;
148    private UserManager mUserManager;
149    private AppOpsManager mAppOps;
150    private MainThreadHandler mMainThreadHandler;
151    private SubscriptionController mSubscriptionController;
152    private SharedPreferences mTelephonySharedPreferences;
153
154    private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
155    private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
156    private static final String PREF_CARRIERS_SUBSCRIBER_PREFIX = "carrier_subscriber_";
157    private static final String PREF_ENABLE_VIDEO_CALLING = "enable_video_calling";
158
159    /**
160     * A request object to use for transmitting data to an ICC.
161     */
162    private static final class IccAPDUArgument {
163        public int channel, cla, command, p1, p2, p3;
164        public String data;
165
166        public IccAPDUArgument(int channel, int cla, int command,
167                int p1, int p2, int p3, String data) {
168            this.channel = channel;
169            this.cla = cla;
170            this.command = command;
171            this.p1 = p1;
172            this.p2 = p2;
173            this.p3 = p3;
174            this.data = data;
175        }
176    }
177
178    /**
179     * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
180     * request after sending. The main thread will notify the request when it is complete.
181     */
182    private static final class MainThreadRequest {
183        /** The argument to use for the request */
184        public Object argument;
185        /** The result of the request that is run on the main thread */
186        public Object result;
187        /** The subscriber id that this request applies to. Null if default. */
188        public Integer subId;
189
190        public MainThreadRequest(Object argument) {
191            this.argument = argument;
192        }
193
194        public MainThreadRequest(Object argument, Integer subId) {
195            this.argument = argument;
196            this.subId = subId;
197        }
198    }
199
200    private static final class IncomingThirdPartyCallArgs {
201        public final ComponentName component;
202        public final String callId;
203        public final String callerDisplayName;
204
205        public IncomingThirdPartyCallArgs(ComponentName component, String callId,
206                String callerDisplayName) {
207            this.component = component;
208            this.callId = callId;
209            this.callerDisplayName = callerDisplayName;
210        }
211    }
212
213    /**
214     * A handler that processes messages on the main thread in the phone process. Since many
215     * of the Phone calls are not thread safe this is needed to shuttle the requests from the
216     * inbound binder threads to the main thread in the phone process.  The Binder thread
217     * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
218     * on, which will be notified when the operation completes and will contain the result of the
219     * request.
220     *
221     * <p>If a MainThreadRequest object is provided in the msg.obj field,
222     * note that request.result must be set to something non-null for the calling thread to
223     * unblock.
224     */
225    private final class MainThreadHandler extends Handler {
226        @Override
227        public void handleMessage(Message msg) {
228            MainThreadRequest request;
229            Message onCompleted;
230            AsyncResult ar;
231            UiccCard uiccCard = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
232            IccAPDUArgument iccArgument;
233
234            switch (msg.what) {
235                case CMD_HANDLE_PIN_MMI: {
236                    request = (MainThreadRequest) msg.obj;
237                    final Phone phone = getPhoneFromRequest(request);
238                    request.result = phone != null ?
239                            getPhoneFromRequest(request).handlePinMmi((String) request.argument)
240                            : false;
241                    // Wake up the requesting thread
242                    synchronized (request) {
243                        request.notifyAll();
244                    }
245                    break;
246                }
247
248                case CMD_HANDLE_NEIGHBORING_CELL:
249                    request = (MainThreadRequest) msg.obj;
250                    onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
251                            request);
252                    mPhone.getNeighboringCids(onCompleted);
253                    break;
254
255                case EVENT_NEIGHBORING_CELL_DONE:
256                    ar = (AsyncResult) msg.obj;
257                    request = (MainThreadRequest) ar.userObj;
258                    if (ar.exception == null && ar.result != null) {
259                        request.result = ar.result;
260                    } else {
261                        // create an empty list to notify the waiting thread
262                        request.result = new ArrayList<NeighboringCellInfo>(0);
263                    }
264                    // Wake up the requesting thread
265                    synchronized (request) {
266                        request.notifyAll();
267                    }
268                    break;
269
270                case CMD_ANSWER_RINGING_CALL:
271                    request = (MainThreadRequest) msg.obj;
272                    int answer_subId = request.subId;
273                    answerRingingCallInternal(answer_subId);
274                    break;
275
276                case CMD_END_CALL:
277                    request = (MainThreadRequest) msg.obj;
278                    int end_subId = request.subId;
279                    final boolean hungUp;
280                    Phone phone = getPhone(end_subId);
281                    if (phone == null) {
282                        if (DBG) log("CMD_END_CALL: no phone for id: " + end_subId);
283                        break;
284                    }
285                    int phoneType = phone.getPhoneType();
286                    if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
287                        // CDMA: If the user presses the Power button we treat it as
288                        // ending the complete call session
289                        hungUp = PhoneUtils.hangupRingingAndActive(getPhone(end_subId));
290                    } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
291                        // GSM: End the call as per the Phone state
292                        hungUp = PhoneUtils.hangup(mCM);
293                    } else {
294                        throw new IllegalStateException("Unexpected phone type: " + phoneType);
295                    }
296                    if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
297                    request.result = hungUp;
298                    // Wake up the requesting thread
299                    synchronized (request) {
300                        request.notifyAll();
301                    }
302                    break;
303
304                case CMD_TRANSMIT_APDU_LOGICAL_CHANNEL:
305                    request = (MainThreadRequest) msg.obj;
306                    iccArgument = (IccAPDUArgument) request.argument;
307                    if (uiccCard == null) {
308                        loge("iccTransmitApduLogicalChannel: No UICC");
309                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
310                        synchronized (request) {
311                            request.notifyAll();
312                        }
313                    } else {
314                        onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE,
315                            request);
316                        uiccCard.iccTransmitApduLogicalChannel(
317                            iccArgument.channel, iccArgument.cla, iccArgument.command,
318                            iccArgument.p1, iccArgument.p2, iccArgument.p3, iccArgument.data,
319                            onCompleted);
320                    }
321                    break;
322
323                case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
324                    ar = (AsyncResult) msg.obj;
325                    request = (MainThreadRequest) ar.userObj;
326                    if (ar.exception == null && ar.result != null) {
327                        request.result = ar.result;
328                    } else {
329                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
330                        if (ar.result == null) {
331                            loge("iccTransmitApduLogicalChannel: Empty response");
332                        } else if (ar.exception instanceof CommandException) {
333                            loge("iccTransmitApduLogicalChannel: CommandException: " +
334                                    ar.exception);
335                        } else {
336                            loge("iccTransmitApduLogicalChannel: Unknown exception");
337                        }
338                    }
339                    synchronized (request) {
340                        request.notifyAll();
341                    }
342                    break;
343
344                case CMD_TRANSMIT_APDU_BASIC_CHANNEL:
345                    request = (MainThreadRequest) msg.obj;
346                    iccArgument = (IccAPDUArgument) request.argument;
347                    if (uiccCard == null) {
348                        loge("iccTransmitApduBasicChannel: No UICC");
349                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
350                        synchronized (request) {
351                            request.notifyAll();
352                        }
353                    } else {
354                        onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE,
355                            request);
356                        uiccCard.iccTransmitApduBasicChannel(
357                            iccArgument.cla, iccArgument.command, iccArgument.p1, iccArgument.p2,
358                            iccArgument.p3, iccArgument.data, onCompleted);
359                    }
360                    break;
361
362                case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE:
363                    ar = (AsyncResult) msg.obj;
364                    request = (MainThreadRequest) ar.userObj;
365                    if (ar.exception == null && ar.result != null) {
366                        request.result = ar.result;
367                    } else {
368                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
369                        if (ar.result == null) {
370                            loge("iccTransmitApduBasicChannel: Empty response");
371                        } else if (ar.exception instanceof CommandException) {
372                            loge("iccTransmitApduBasicChannel: CommandException: " +
373                                    ar.exception);
374                        } else {
375                            loge("iccTransmitApduBasicChannel: Unknown exception");
376                        }
377                    }
378                    synchronized (request) {
379                        request.notifyAll();
380                    }
381                    break;
382
383                case CMD_EXCHANGE_SIM_IO:
384                    request = (MainThreadRequest) msg.obj;
385                    iccArgument = (IccAPDUArgument) request.argument;
386                    if (uiccCard == null) {
387                        loge("iccExchangeSimIO: No UICC");
388                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
389                        synchronized (request) {
390                            request.notifyAll();
391                        }
392                    } else {
393                        onCompleted = obtainMessage(EVENT_EXCHANGE_SIM_IO_DONE,
394                                request);
395                        uiccCard.iccExchangeSimIO(iccArgument.cla, /* fileID */
396                                iccArgument.command, iccArgument.p1, iccArgument.p2, iccArgument.p3,
397                                iccArgument.data, onCompleted);
398                    }
399                    break;
400
401                case EVENT_EXCHANGE_SIM_IO_DONE:
402                    ar = (AsyncResult) msg.obj;
403                    request = (MainThreadRequest) ar.userObj;
404                    if (ar.exception == null && ar.result != null) {
405                        request.result = ar.result;
406                    } else {
407                        request.result = new IccIoResult(0x6f, 0, (byte[])null);
408                    }
409                    synchronized (request) {
410                        request.notifyAll();
411                    }
412                    break;
413
414                case CMD_SEND_ENVELOPE:
415                    request = (MainThreadRequest) msg.obj;
416                    if (uiccCard == null) {
417                        loge("sendEnvelopeWithStatus: No UICC");
418                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
419                        synchronized (request) {
420                            request.notifyAll();
421                        }
422                    } else {
423                        onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
424                        uiccCard.sendEnvelopeWithStatus((String)request.argument, onCompleted);
425                    }
426                    break;
427
428                case EVENT_SEND_ENVELOPE_DONE:
429                    ar = (AsyncResult) msg.obj;
430                    request = (MainThreadRequest) ar.userObj;
431                    if (ar.exception == null && ar.result != null) {
432                        request.result = ar.result;
433                    } else {
434                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
435                        if (ar.result == null) {
436                            loge("sendEnvelopeWithStatus: Empty response");
437                        } else if (ar.exception instanceof CommandException) {
438                            loge("sendEnvelopeWithStatus: CommandException: " +
439                                    ar.exception);
440                        } else {
441                            loge("sendEnvelopeWithStatus: exception:" + ar.exception);
442                        }
443                    }
444                    synchronized (request) {
445                        request.notifyAll();
446                    }
447                    break;
448
449                case CMD_OPEN_CHANNEL:
450                    request = (MainThreadRequest) msg.obj;
451                    if (uiccCard == null) {
452                        loge("iccOpenLogicalChannel: No UICC");
453                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
454                        synchronized (request) {
455                            request.notifyAll();
456                        }
457                    } else {
458                        onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
459                        uiccCard.iccOpenLogicalChannel((String)request.argument, onCompleted);
460                    }
461                    break;
462
463                case EVENT_OPEN_CHANNEL_DONE:
464                    ar = (AsyncResult) msg.obj;
465                    request = (MainThreadRequest) ar.userObj;
466                    IccOpenLogicalChannelResponse openChannelResp;
467                    if (ar.exception == null && ar.result != null) {
468                        int[] result = (int[]) ar.result;
469                        int channelId = result[0];
470                        byte[] selectResponse = null;
471                        if (result.length > 1) {
472                            selectResponse = new byte[result.length - 1];
473                            for (int i = 1; i < result.length; ++i) {
474                                selectResponse[i - 1] = (byte) result[i];
475                            }
476                        }
477                        openChannelResp = new IccOpenLogicalChannelResponse(channelId,
478                            IccOpenLogicalChannelResponse.STATUS_NO_ERROR, selectResponse);
479                    } else {
480                        if (ar.result == null) {
481                            loge("iccOpenLogicalChannel: Empty response");
482                        }
483                        if (ar.exception != null) {
484                            loge("iccOpenLogicalChannel: Exception: " + ar.exception);
485                        }
486
487                        int errorCode = IccOpenLogicalChannelResponse.STATUS_UNKNOWN_ERROR;
488                        if (ar.exception instanceof CommandException) {
489                            CommandException.Error error =
490                                ((CommandException) (ar.exception)).getCommandError();
491                            if (error == CommandException.Error.MISSING_RESOURCE) {
492                                errorCode = IccOpenLogicalChannelResponse.STATUS_MISSING_RESOURCE;
493                            } else if (error == CommandException.Error.NO_SUCH_ELEMENT) {
494                                errorCode = IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT;
495                            }
496                        }
497                        openChannelResp = new IccOpenLogicalChannelResponse(
498                            IccOpenLogicalChannelResponse.INVALID_CHANNEL, errorCode, null);
499                    }
500                    request.result = openChannelResp;
501                    synchronized (request) {
502                        request.notifyAll();
503                    }
504                    break;
505
506                case CMD_CLOSE_CHANNEL:
507                    request = (MainThreadRequest) msg.obj;
508                    if (uiccCard == null) {
509                        loge("iccCloseLogicalChannel: No UICC");
510                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
511                        synchronized (request) {
512                            request.notifyAll();
513                        }
514                    } else {
515                        onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
516                        uiccCard.iccCloseLogicalChannel((Integer) request.argument, onCompleted);
517                    }
518                    break;
519
520                case EVENT_CLOSE_CHANNEL_DONE:
521                    handleNullReturnEvent(msg, "iccCloseLogicalChannel");
522                    break;
523
524                case CMD_NV_READ_ITEM:
525                    request = (MainThreadRequest) msg.obj;
526                    onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
527                    mPhone.nvReadItem((Integer) request.argument, onCompleted);
528                    break;
529
530                case EVENT_NV_READ_ITEM_DONE:
531                    ar = (AsyncResult) msg.obj;
532                    request = (MainThreadRequest) ar.userObj;
533                    if (ar.exception == null && ar.result != null) {
534                        request.result = ar.result;     // String
535                    } else {
536                        request.result = "";
537                        if (ar.result == null) {
538                            loge("nvReadItem: Empty response");
539                        } else if (ar.exception instanceof CommandException) {
540                            loge("nvReadItem: CommandException: " +
541                                    ar.exception);
542                        } else {
543                            loge("nvReadItem: Unknown exception");
544                        }
545                    }
546                    synchronized (request) {
547                        request.notifyAll();
548                    }
549                    break;
550
551                case CMD_NV_WRITE_ITEM:
552                    request = (MainThreadRequest) msg.obj;
553                    onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
554                    Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
555                    mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
556                    break;
557
558                case EVENT_NV_WRITE_ITEM_DONE:
559                    handleNullReturnEvent(msg, "nvWriteItem");
560                    break;
561
562                case CMD_NV_WRITE_CDMA_PRL:
563                    request = (MainThreadRequest) msg.obj;
564                    onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
565                    mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
566                    break;
567
568                case EVENT_NV_WRITE_CDMA_PRL_DONE:
569                    handleNullReturnEvent(msg, "nvWriteCdmaPrl");
570                    break;
571
572                case CMD_NV_RESET_CONFIG:
573                    request = (MainThreadRequest) msg.obj;
574                    onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
575                    mPhone.nvResetConfig((Integer) request.argument, onCompleted);
576                    break;
577
578                case EVENT_NV_RESET_CONFIG_DONE:
579                    handleNullReturnEvent(msg, "nvResetConfig");
580                    break;
581
582                case CMD_GET_PREFERRED_NETWORK_TYPE:
583                    request = (MainThreadRequest) msg.obj;
584                    onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
585                    getPhoneFromRequest(request).getPreferredNetworkType(onCompleted);
586                    break;
587
588                case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
589                    ar = (AsyncResult) msg.obj;
590                    request = (MainThreadRequest) ar.userObj;
591                    if (ar.exception == null && ar.result != null) {
592                        request.result = ar.result;     // Integer
593                    } else {
594                        request.result = -1;
595                        if (ar.result == null) {
596                            loge("getPreferredNetworkType: Empty response");
597                        } else if (ar.exception instanceof CommandException) {
598                            loge("getPreferredNetworkType: CommandException: " +
599                                    ar.exception);
600                        } else {
601                            loge("getPreferredNetworkType: Unknown exception");
602                        }
603                    }
604                    synchronized (request) {
605                        request.notifyAll();
606                    }
607                    break;
608
609                case CMD_SET_PREFERRED_NETWORK_TYPE:
610                    request = (MainThreadRequest) msg.obj;
611                    onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
612                    int networkType = (Integer) request.argument;
613                    getPhoneFromRequest(request).setPreferredNetworkType(networkType, onCompleted);
614                    break;
615
616                case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
617                    handleNullReturnEvent(msg, "setPreferredNetworkType");
618                    break;
619
620                case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
621                    request = (MainThreadRequest)msg.obj;
622                    onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
623                    mPhone.invokeOemRilRequestRaw((byte[])request.argument, onCompleted);
624                    break;
625
626                case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
627                    ar = (AsyncResult)msg.obj;
628                    request = (MainThreadRequest)ar.userObj;
629                    request.result = ar;
630                    synchronized (request) {
631                        request.notifyAll();
632                    }
633                    break;
634
635                case CMD_SET_VOICEMAIL_NUMBER:
636                    request = (MainThreadRequest) msg.obj;
637                    onCompleted = obtainMessage(EVENT_SET_VOICEMAIL_NUMBER_DONE, request);
638                    Pair<String, String> tagNum = (Pair<String, String>) request.argument;
639                    getPhoneFromRequest(request).setVoiceMailNumber(tagNum.first, tagNum.second,
640                            onCompleted);
641                    break;
642
643                case EVENT_SET_VOICEMAIL_NUMBER_DONE:
644                    handleNullReturnEvent(msg, "setVoicemailNumber");
645                    break;
646
647                case CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC:
648                    request = (MainThreadRequest) msg.obj;
649                    onCompleted = obtainMessage(EVENT_SET_NETWORK_SELECTION_MODE_AUTOMATIC_DONE,
650                            request);
651                    getPhoneFromRequest(request).setNetworkSelectionModeAutomatic(onCompleted);
652                    break;
653
654                case EVENT_SET_NETWORK_SELECTION_MODE_AUTOMATIC_DONE:
655                    handleNullReturnEvent(msg, "setNetworkSelectionModeAutomatic");
656                    break;
657
658                case CMD_PERFORM_NETWORK_SCAN:
659                    request = (MainThreadRequest) msg.obj;
660                    onCompleted = obtainMessage(EVENT_PERFORM_NETWORK_SCAN_DONE, request);
661                    getPhoneFromRequest(request).getAvailableNetworks(onCompleted);
662                    break;
663
664                case EVENT_PERFORM_NETWORK_SCAN_DONE:
665                    ar = (AsyncResult) msg.obj;
666                    request = (MainThreadRequest) ar.userObj;
667                    CellNetworkScanResult cellScanResult;
668                    if (ar.exception == null && ar.result != null) {
669                        cellScanResult = new CellNetworkScanResult(
670                                CellNetworkScanResult.STATUS_SUCCESS,
671                                (List<OperatorInfo>) ar.result);
672                    } else {
673                        if (ar.result == null) {
674                            loge("getCellNetworkScanResults: Empty response");
675                        }
676                        if (ar.exception != null) {
677                            loge("getCellNetworkScanResults: Exception: " + ar.exception);
678                        }
679                        int errorCode = CellNetworkScanResult.STATUS_UNKNOWN_ERROR;
680                        if (ar.exception instanceof CommandException) {
681                            CommandException.Error error =
682                                ((CommandException) (ar.exception)).getCommandError();
683                            if (error == CommandException.Error.RADIO_NOT_AVAILABLE) {
684                                errorCode = CellNetworkScanResult.STATUS_RADIO_NOT_AVAILABLE;
685                            } else if (error == CommandException.Error.GENERIC_FAILURE) {
686                                errorCode = CellNetworkScanResult.STATUS_RADIO_GENERIC_FAILURE;
687                            }
688                        }
689                        cellScanResult = new CellNetworkScanResult(errorCode, null);
690                    }
691                    request.result = cellScanResult;
692                    synchronized (request) {
693                        request.notifyAll();
694                    }
695                    break;
696
697                case CMD_SET_NETWORK_SELECTION_MODE_MANUAL:
698                    request = (MainThreadRequest) msg.obj;
699                    OperatorInfo operator = (OperatorInfo) request.argument;
700                    onCompleted = obtainMessage(EVENT_SET_NETWORK_SELECTION_MODE_MANUAL_DONE,
701                            request);
702                    getPhoneFromRequest(request).selectNetworkManually(operator, onCompleted);
703                    break;
704
705                case EVENT_SET_NETWORK_SELECTION_MODE_MANUAL_DONE:
706                    handleNullReturnEvent(msg, "setNetworkSelectionModeManual");
707                    break;
708
709                case CMD_GET_MODEM_ACTIVITY_INFO:
710                    request = (MainThreadRequest) msg.obj;
711                    onCompleted = obtainMessage(EVENT_GET_MODEM_ACTIVITY_INFO_DONE, request);
712                    mPhone.getModemActivityInfo(onCompleted);
713                    break;
714
715                case EVENT_GET_MODEM_ACTIVITY_INFO_DONE:
716                    ar = (AsyncResult) msg.obj;
717                    request = (MainThreadRequest) ar.userObj;
718                    if (ar.exception == null && ar.result != null) {
719                        request.result = ar.result;
720                    } else {
721                        if (ar.result == null) {
722                            loge("queryModemActivityInfo: Empty response");
723                        } else if (ar.exception instanceof CommandException) {
724                            loge("queryModemActivityInfo: CommandException: " +
725                                    ar.exception);
726                        } else {
727                            loge("queryModemActivityInfo: Unknown exception");
728                        }
729                    }
730                    synchronized (request) {
731                        request.notifyAll();
732                    }
733                    break;
734
735                default:
736                    Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
737                    break;
738            }
739        }
740
741        private void handleNullReturnEvent(Message msg, String command) {
742            AsyncResult ar = (AsyncResult) msg.obj;
743            MainThreadRequest request = (MainThreadRequest) ar.userObj;
744            if (ar.exception == null) {
745                request.result = true;
746            } else {
747                request.result = false;
748                if (ar.exception instanceof CommandException) {
749                    loge(command + ": CommandException: " + ar.exception);
750                } else {
751                    loge(command + ": Unknown exception");
752                }
753            }
754            synchronized (request) {
755                request.notifyAll();
756            }
757        }
758    }
759
760    /**
761     * Posts the specified command to be executed on the main thread,
762     * waits for the request to complete, and returns the result.
763     * @see #sendRequestAsync
764     */
765    private Object sendRequest(int command, Object argument) {
766        return sendRequest(command, argument, null);
767    }
768
769    /**
770     * Posts the specified command to be executed on the main thread,
771     * waits for the request to complete, and returns the result.
772     * @see #sendRequestAsync
773     */
774    private Object sendRequest(int command, Object argument, Integer subId) {
775        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
776            throw new RuntimeException("This method will deadlock if called from the main thread.");
777        }
778
779        MainThreadRequest request = new MainThreadRequest(argument, subId);
780        Message msg = mMainThreadHandler.obtainMessage(command, request);
781        msg.sendToTarget();
782
783        // Wait for the request to complete
784        synchronized (request) {
785            while (request.result == null) {
786                try {
787                    request.wait();
788                } catch (InterruptedException e) {
789                    // Do nothing, go back and wait until the request is complete
790                }
791            }
792        }
793        return request.result;
794    }
795
796    /**
797     * Asynchronous ("fire and forget") version of sendRequest():
798     * Posts the specified command to be executed on the main thread, and
799     * returns immediately.
800     * @see #sendRequest
801     */
802    private void sendRequestAsync(int command) {
803        mMainThreadHandler.sendEmptyMessage(command);
804    }
805
806    /**
807     * Same as {@link #sendRequestAsync(int)} except it takes an argument.
808     * @see {@link #sendRequest(int,Object)}
809     */
810    private void sendRequestAsync(int command, Object argument) {
811        MainThreadRequest request = new MainThreadRequest(argument);
812        Message msg = mMainThreadHandler.obtainMessage(command, request);
813        msg.sendToTarget();
814    }
815
816    /**
817     * Initialize the singleton PhoneInterfaceManager instance.
818     * This is only done once, at startup, from PhoneApp.onCreate().
819     */
820    /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
821        synchronized (PhoneInterfaceManager.class) {
822            if (sInstance == null) {
823                sInstance = new PhoneInterfaceManager(app, phone);
824            } else {
825                Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
826            }
827            return sInstance;
828        }
829    }
830
831    /** Private constructor; @see init() */
832    private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
833        mApp = app;
834        mPhone = phone;
835        mCM = PhoneGlobals.getInstance().mCM;
836        mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
837        mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
838        mMainThreadHandler = new MainThreadHandler();
839        mTelephonySharedPreferences =
840                PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
841        mSubscriptionController = SubscriptionController.getInstance();
842
843        publish();
844    }
845
846    private void publish() {
847        if (DBG) log("publish: " + this);
848
849        ServiceManager.addService("phone", this);
850    }
851
852    private Phone getPhoneFromRequest(MainThreadRequest request) {
853        return (request.subId == null) ? mPhone : getPhone(request.subId);
854    }
855
856    // returns phone associated with the subId.
857    private Phone getPhone(int subId) {
858        return PhoneFactory.getPhone(mSubscriptionController.getPhoneId(subId));
859    }
860    //
861    // Implementation of the ITelephony interface.
862    //
863
864    public void dial(String number) {
865        dialForSubscriber(getPreferredVoiceSubscription(), number);
866    }
867
868    public void dialForSubscriber(int subId, String number) {
869        if (DBG) log("dial: " + number);
870        // No permission check needed here: This is just a wrapper around the
871        // ACTION_DIAL intent, which is available to any app since it puts up
872        // the UI before it does anything.
873
874        String url = createTelUrl(number);
875        if (url == null) {
876            return;
877        }
878
879        // PENDING: should we just silently fail if phone is offhook or ringing?
880        PhoneConstants.State state = mCM.getState(subId);
881        if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
882            Intent  intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
883            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
884            mApp.startActivity(intent);
885        }
886    }
887
888    public void call(String callingPackage, String number) {
889        callForSubscriber(getPreferredVoiceSubscription(), callingPackage, number);
890    }
891
892    public void callForSubscriber(int subId, String callingPackage, String number) {
893        if (DBG) log("call: " + number);
894
895        // This is just a wrapper around the ACTION_CALL intent, but we still
896        // need to do a permission check since we're calling startActivity()
897        // from the context of the phone app.
898        enforceCallPermission();
899
900        if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
901                != AppOpsManager.MODE_ALLOWED) {
902            return;
903        }
904
905        String url = createTelUrl(number);
906        if (url == null) {
907            return;
908        }
909
910        boolean isValid = false;
911        final List<SubscriptionInfo> slist = getActiveSubscriptionInfoList();
912        if (slist != null) {
913            for (SubscriptionInfo subInfoRecord : slist) {
914                if (subInfoRecord.getSubscriptionId() == subId) {
915                    isValid = true;
916                    break;
917                }
918            }
919        }
920        if (isValid == false) {
921            return;
922        }
923
924        Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
925        intent.putExtra(SUBSCRIPTION_KEY, subId);
926        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
927        mApp.startActivity(intent);
928    }
929
930    /**
931     * End a call based on call state
932     * @return true is a call was ended
933     */
934    public boolean endCall() {
935        return endCallForSubscriber(getDefaultSubscription());
936    }
937
938    /**
939     * End a call based on the call state of the subId
940     * @return true is a call was ended
941     */
942    public boolean endCallForSubscriber(int subId) {
943        enforceCallPermission();
944        return (Boolean) sendRequest(CMD_END_CALL, null, new Integer(subId));
945    }
946
947    public void answerRingingCall() {
948        answerRingingCallForSubscriber(getDefaultSubscription());
949    }
950
951    public void answerRingingCallForSubscriber(int subId) {
952        if (DBG) log("answerRingingCall...");
953        // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
954        // but that can probably wait till the big TelephonyManager API overhaul.
955        // For now, protect this call with the MODIFY_PHONE_STATE permission.
956        enforceModifyPermission();
957        sendRequest(CMD_ANSWER_RINGING_CALL, null, new Integer(subId));
958    }
959
960    /**
961     * Make the actual telephony calls to implement answerRingingCall().
962     * This should only be called from the main thread of the Phone app.
963     * @see #answerRingingCall
964     *
965     * TODO: it would be nice to return true if we answered the call, or
966     * false if there wasn't actually a ringing incoming call, or some
967     * other error occurred.  (In other words, pass back the return value
968     * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
969     * But that would require calling this method via sendRequest() rather
970     * than sendRequestAsync(), and right now we don't actually *need* that
971     * return value, so let's just return void for now.
972     */
973    private void answerRingingCallInternal(int subId) {
974        final boolean hasRingingCall = !getPhone(subId).getRingingCall().isIdle();
975        if (hasRingingCall) {
976            final boolean hasActiveCall = !getPhone(subId).getForegroundCall().isIdle();
977            final boolean hasHoldingCall = !getPhone(subId).getBackgroundCall().isIdle();
978            if (hasActiveCall && hasHoldingCall) {
979                // Both lines are in use!
980                // TODO: provide a flag to let the caller specify what
981                // policy to use if both lines are in use.  (The current
982                // behavior is hardwired to "answer incoming, end ongoing",
983                // which is how the CALL button is specced to behave.)
984                PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
985                return;
986            } else {
987                // answerCall() will automatically hold the current active
988                // call, if there is one.
989                PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
990                return;
991            }
992        } else {
993            // No call was ringing.
994            return;
995        }
996    }
997
998    /**
999     * This method is no longer used and can be removed once TelephonyManager stops referring to it.
1000     */
1001    public void silenceRinger() {
1002        Log.e(LOG_TAG, "silenseRinger not supported");
1003    }
1004
1005    public boolean isOffhook() {
1006        return isOffhookForSubscriber(getDefaultSubscription());
1007    }
1008
1009    public boolean isOffhookForSubscriber(int subId) {
1010        final Phone phone = getPhone(subId);
1011        if (phone != null) {
1012            return (phone.getState() == PhoneConstants.State.OFFHOOK);
1013        } else {
1014            return false;
1015        }
1016    }
1017
1018    public boolean isRinging() {
1019        return (isRingingForSubscriber(getDefaultSubscription()));
1020    }
1021
1022    public boolean isRingingForSubscriber(int subId) {
1023        final Phone phone = getPhone(subId);
1024        if (phone != null) {
1025            return (phone.getState() == PhoneConstants.State.RINGING);
1026        } else {
1027            return false;
1028        }
1029    }
1030
1031    public boolean isIdle() {
1032        return isIdleForSubscriber(getDefaultSubscription());
1033    }
1034
1035    public boolean isIdleForSubscriber(int subId) {
1036        final Phone phone = getPhone(subId);
1037        if (phone != null) {
1038            return (phone.getState() == PhoneConstants.State.IDLE);
1039        } else {
1040            return false;
1041        }
1042    }
1043
1044    public boolean isSimPinEnabled(String callingPackage) {
1045        if (!canReadPhoneState(callingPackage, "isSimPinEnabled")) {
1046            return false;
1047        }
1048
1049        return (PhoneGlobals.getInstance().isSimPinEnabled());
1050    }
1051
1052    public boolean supplyPin(String pin) {
1053        return supplyPinForSubscriber(getDefaultSubscription(), pin);
1054    }
1055
1056    public boolean supplyPinForSubscriber(int subId, String pin) {
1057        int [] resultArray = supplyPinReportResultForSubscriber(subId, pin);
1058        return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
1059    }
1060
1061    public boolean supplyPuk(String puk, String pin) {
1062        return supplyPukForSubscriber(getDefaultSubscription(), puk, pin);
1063    }
1064
1065    public boolean supplyPukForSubscriber(int subId, String puk, String pin) {
1066        int [] resultArray = supplyPukReportResultForSubscriber(subId, puk, pin);
1067        return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
1068    }
1069
1070    /** {@hide} */
1071    public int[] supplyPinReportResult(String pin) {
1072        return supplyPinReportResultForSubscriber(getDefaultSubscription(), pin);
1073    }
1074
1075    public int[] supplyPinReportResultForSubscriber(int subId, String pin) {
1076        enforceModifyPermission();
1077        final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
1078        checkSimPin.start();
1079        return checkSimPin.unlockSim(null, pin);
1080    }
1081
1082    /** {@hide} */
1083    public int[] supplyPukReportResult(String puk, String pin) {
1084        return supplyPukReportResultForSubscriber(getDefaultSubscription(), puk, pin);
1085    }
1086
1087    public int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin) {
1088        enforceModifyPermission();
1089        final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
1090        checkSimPuk.start();
1091        return checkSimPuk.unlockSim(puk, pin);
1092    }
1093
1094    /**
1095     * Helper thread to turn async call to SimCard#supplyPin into
1096     * a synchronous one.
1097     */
1098    private static class UnlockSim extends Thread {
1099
1100        private final IccCard mSimCard;
1101
1102        private boolean mDone = false;
1103        private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
1104        private int mRetryCount = -1;
1105
1106        // For replies from SimCard interface
1107        private Handler mHandler;
1108
1109        // For async handler to identify request type
1110        private static final int SUPPLY_PIN_COMPLETE = 100;
1111
1112        public UnlockSim(IccCard simCard) {
1113            mSimCard = simCard;
1114        }
1115
1116        @Override
1117        public void run() {
1118            Looper.prepare();
1119            synchronized (UnlockSim.this) {
1120                mHandler = new Handler() {
1121                    @Override
1122                    public void handleMessage(Message msg) {
1123                        AsyncResult ar = (AsyncResult) msg.obj;
1124                        switch (msg.what) {
1125                            case SUPPLY_PIN_COMPLETE:
1126                                Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
1127                                synchronized (UnlockSim.this) {
1128                                    mRetryCount = msg.arg1;
1129                                    if (ar.exception != null) {
1130                                        if (ar.exception instanceof CommandException &&
1131                                                ((CommandException)(ar.exception)).getCommandError()
1132                                                == CommandException.Error.PASSWORD_INCORRECT) {
1133                                            mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
1134                                        } else {
1135                                            mResult = PhoneConstants.PIN_GENERAL_FAILURE;
1136                                        }
1137                                    } else {
1138                                        mResult = PhoneConstants.PIN_RESULT_SUCCESS;
1139                                    }
1140                                    mDone = true;
1141                                    UnlockSim.this.notifyAll();
1142                                }
1143                                break;
1144                        }
1145                    }
1146                };
1147                UnlockSim.this.notifyAll();
1148            }
1149            Looper.loop();
1150        }
1151
1152        /*
1153         * Use PIN or PUK to unlock SIM card
1154         *
1155         * If PUK is null, unlock SIM card with PIN
1156         *
1157         * If PUK is not null, unlock SIM card with PUK and set PIN code
1158         */
1159        synchronized int[] unlockSim(String puk, String pin) {
1160
1161            while (mHandler == null) {
1162                try {
1163                    wait();
1164                } catch (InterruptedException e) {
1165                    Thread.currentThread().interrupt();
1166                }
1167            }
1168            Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
1169
1170            if (puk == null) {
1171                mSimCard.supplyPin(pin, callback);
1172            } else {
1173                mSimCard.supplyPuk(puk, pin, callback);
1174            }
1175
1176            while (!mDone) {
1177                try {
1178                    Log.d(LOG_TAG, "wait for done");
1179                    wait();
1180                } catch (InterruptedException e) {
1181                    // Restore the interrupted status
1182                    Thread.currentThread().interrupt();
1183                }
1184            }
1185            Log.d(LOG_TAG, "done");
1186            int[] resultArray = new int[2];
1187            resultArray[0] = mResult;
1188            resultArray[1] = mRetryCount;
1189            return resultArray;
1190        }
1191    }
1192
1193    public void updateServiceLocation() {
1194        updateServiceLocationForSubscriber(getDefaultSubscription());
1195
1196    }
1197
1198    public void updateServiceLocationForSubscriber(int subId) {
1199        // No permission check needed here: this call is harmless, and it's
1200        // needed for the ServiceState.requestStateUpdate() call (which is
1201        // already intentionally exposed to 3rd parties.)
1202        final Phone phone = getPhone(subId);
1203        if (phone != null) {
1204            phone.updateServiceLocation();
1205        }
1206    }
1207
1208    public boolean isRadioOn() {
1209        return isRadioOnForSubscriber(getDefaultSubscription());
1210    }
1211
1212    public boolean isRadioOnForSubscriber(int subId) {
1213        final Phone phone = getPhone(subId);
1214        if (phone != null) {
1215            return phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
1216        } else {
1217            return false;
1218        }
1219    }
1220
1221    public void toggleRadioOnOff() {
1222        toggleRadioOnOffForSubscriber(getDefaultSubscription());
1223
1224    }
1225
1226    public void toggleRadioOnOffForSubscriber(int subId) {
1227        enforceModifyPermission();
1228        final Phone phone = getPhone(subId);
1229        if (phone != null) {
1230            phone.setRadioPower(!isRadioOnForSubscriber(subId));
1231        }
1232    }
1233
1234    public boolean setRadio(boolean turnOn) {
1235        return setRadioForSubscriber(getDefaultSubscription(), turnOn);
1236    }
1237
1238    public boolean setRadioForSubscriber(int subId, boolean turnOn) {
1239        enforceModifyPermission();
1240        final Phone phone = getPhone(subId);
1241        if (phone == null) {
1242            return false;
1243        }
1244        if ((phone.getServiceState().getState() !=
1245                ServiceState.STATE_POWER_OFF) != turnOn) {
1246            toggleRadioOnOffForSubscriber(subId);
1247        }
1248        return true;
1249    }
1250
1251    public boolean needMobileRadioShutdown() {
1252        /*
1253         * If any of the Radios are available, it will need to be
1254         * shutdown. So return true if any Radio is available.
1255         */
1256        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1257            Phone phone = PhoneFactory.getPhone(i);
1258            if (phone != null && phone.isRadioAvailable()) return true;
1259        }
1260        logv(TelephonyManager.getDefault().getPhoneCount() + " Phones are shutdown.");
1261        return false;
1262    }
1263
1264    public void shutdownMobileRadios() {
1265        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1266            logv("Shutting down Phone " + i);
1267            shutdownRadioUsingPhoneId(i);
1268        }
1269    }
1270
1271    private void shutdownRadioUsingPhoneId(int phoneId) {
1272        enforceModifyPermission();
1273        Phone phone = PhoneFactory.getPhone(phoneId);
1274        if (phone != null && phone.isRadioAvailable()) {
1275            phone.shutdownRadio();
1276        }
1277    }
1278
1279    public boolean setRadioPower(boolean turnOn) {
1280        return setRadioPowerForSubscriber(getDefaultSubscription(), turnOn);
1281    }
1282
1283    public boolean setRadioPowerForSubscriber(int subId, boolean turnOn) {
1284        enforceModifyPermission();
1285        final Phone phone = getPhone(subId);
1286        if (phone != null) {
1287            phone.setRadioPower(turnOn);
1288            return true;
1289        } else {
1290            return false;
1291        }
1292    }
1293
1294    // FIXME: subId version needed
1295    @Override
1296    public boolean enableDataConnectivity() {
1297        enforceModifyPermission();
1298        int subId = mSubscriptionController.getDefaultDataSubId();
1299        final Phone phone = getPhone(subId);
1300        if (phone != null) {
1301            phone.setDataEnabled(true);
1302            return true;
1303        } else {
1304            return false;
1305        }
1306    }
1307
1308    // FIXME: subId version needed
1309    @Override
1310    public boolean disableDataConnectivity() {
1311        enforceModifyPermission();
1312        int subId = mSubscriptionController.getDefaultDataSubId();
1313        final Phone phone = getPhone(subId);
1314        if (phone != null) {
1315            phone.setDataEnabled(false);
1316            return true;
1317        } else {
1318            return false;
1319        }
1320    }
1321
1322    // FIXME: subId version needed
1323    @Override
1324    public boolean isDataConnectivityPossible() {
1325        int subId = mSubscriptionController.getDefaultDataSubId();
1326        final Phone phone = getPhone(subId);
1327        if (phone != null) {
1328            return phone.isDataConnectivityPossible();
1329        } else {
1330            return false;
1331        }
1332    }
1333
1334    public boolean handlePinMmi(String dialString) {
1335        return handlePinMmiForSubscriber(getDefaultSubscription(), dialString);
1336    }
1337
1338    public boolean handlePinMmiForSubscriber(int subId, String dialString) {
1339        enforceModifyPermission();
1340        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
1341            return false;
1342        }
1343        return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
1344    }
1345
1346    public int getCallState() {
1347        return getCallStateForSubscriber(getDefaultSubscription());
1348    }
1349
1350    public int getCallStateForSubscriber(int subId) {
1351        return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
1352    }
1353
1354    @Override
1355    public int getDataState() {
1356        Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
1357        if (phone != null) {
1358            return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
1359        } else {
1360            return DefaultPhoneNotifier.convertDataState(PhoneConstants.DataState.DISCONNECTED);
1361        }
1362    }
1363
1364    @Override
1365    public int getDataActivity() {
1366        Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
1367        if (phone != null) {
1368            return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
1369        } else {
1370            return TelephonyManager.DATA_ACTIVITY_NONE;
1371        }
1372    }
1373
1374    @Override
1375    public Bundle getCellLocation(String callingPackage) {
1376        enforceFineOrCoarseLocationPermission("getCellLocation");
1377
1378        // OP_COARSE_LOCATION controls both fine and coarse location.
1379        if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(),
1380                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1381            log("getCellLocation: returning null; mode != allowed");
1382            return null;
1383        }
1384
1385        if (checkIfCallerIsSelfOrForegroundUser()) {
1386            if (DBG_LOC) log("getCellLocation: is active user");
1387            Bundle data = new Bundle();
1388            Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
1389            if (phone == null) {
1390                return null;
1391            }
1392            phone.getCellLocation().fillInNotifierBundle(data);
1393            return data;
1394        } else {
1395            log("getCellLocation: suppress non-active user");
1396            return null;
1397        }
1398    }
1399
1400    private void enforceFineOrCoarseLocationPermission(String message) {
1401        try {
1402            mApp.enforceCallingOrSelfPermission(
1403                    android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1404        } catch (SecurityException e) {
1405            // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1406            // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1407            // is the weaker precondition
1408            mApp.enforceCallingOrSelfPermission(
1409                    android.Manifest.permission.ACCESS_COARSE_LOCATION, message);
1410        }
1411    }
1412
1413
1414    @Override
1415    public void enableLocationUpdates() {
1416        enableLocationUpdatesForSubscriber(getDefaultSubscription());
1417    }
1418
1419    @Override
1420    public void enableLocationUpdatesForSubscriber(int subId) {
1421        mApp.enforceCallingOrSelfPermission(
1422                android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
1423        final Phone phone = getPhone(subId);
1424        if (phone != null) {
1425            phone.enableLocationUpdates();
1426        }
1427    }
1428
1429    @Override
1430    public void disableLocationUpdates() {
1431        disableLocationUpdatesForSubscriber(getDefaultSubscription());
1432    }
1433
1434    @Override
1435    public void disableLocationUpdatesForSubscriber(int subId) {
1436        mApp.enforceCallingOrSelfPermission(
1437                android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
1438        final Phone phone = getPhone(subId);
1439        if (phone != null) {
1440            phone.disableLocationUpdates();
1441        }
1442    }
1443
1444    @Override
1445    @SuppressWarnings("unchecked")
1446    public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1447        enforceFineOrCoarseLocationPermission("getNeighboringCellInfo");
1448
1449        // OP_COARSE_LOCATION controls both fine and coarse location.
1450        if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(),
1451                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1452            return null;
1453        }
1454
1455        if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1456                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1457            return null;
1458        }
1459
1460        if (checkIfCallerIsSelfOrForegroundUser()) {
1461            if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1462
1463            ArrayList<NeighboringCellInfo> cells = null;
1464
1465            try {
1466                cells = (ArrayList<NeighboringCellInfo>) sendRequest(
1467                        CMD_HANDLE_NEIGHBORING_CELL, null, null);
1468            } catch (RuntimeException e) {
1469                Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
1470            }
1471            return cells;
1472        } else {
1473            if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1474            return null;
1475        }
1476    }
1477
1478
1479    @Override
1480    public List<CellInfo> getAllCellInfo(String callingPackage) {
1481        enforceFineOrCoarseLocationPermission("getAllCellInfo");
1482
1483        // OP_COARSE_LOCATION controls both fine and coarse location.
1484        if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(),
1485                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1486            return null;
1487        }
1488
1489        if (checkIfCallerIsSelfOrForegroundUser()) {
1490            if (DBG_LOC) log("getAllCellInfo: is active user");
1491            List<CellInfo> cellInfos = new ArrayList<CellInfo>();
1492            for (Phone phone : PhoneFactory.getPhones()) {
1493                cellInfos.addAll(phone.getAllCellInfo());
1494            }
1495            return cellInfos;
1496        } else {
1497            if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1498            return null;
1499        }
1500    }
1501
1502    @Override
1503    public void setCellInfoListRate(int rateInMillis) {
1504        mPhone.setCellInfoListRate(rateInMillis);
1505    }
1506
1507    //
1508    // Internal helper methods.
1509    //
1510
1511    private static boolean checkIfCallerIsSelfOrForegroundUser() {
1512        boolean ok;
1513
1514        boolean self = Binder.getCallingUid() == Process.myUid();
1515        if (!self) {
1516            // Get the caller's user id then clear the calling identity
1517            // which will be restored in the finally clause.
1518            int callingUser = UserHandle.getCallingUserId();
1519            long ident = Binder.clearCallingIdentity();
1520
1521            try {
1522                // With calling identity cleared the current user is the foreground user.
1523                int foregroundUser = ActivityManager.getCurrentUser();
1524                ok = (foregroundUser == callingUser);
1525                if (DBG_LOC) {
1526                    log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1527                            + " callingUser=" + callingUser + " ok=" + ok);
1528                }
1529            } catch (Exception ex) {
1530                if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1531                ok = false;
1532            } finally {
1533                Binder.restoreCallingIdentity(ident);
1534            }
1535        } else {
1536            if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1537            ok = true;
1538        }
1539        if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1540        return ok;
1541    }
1542
1543    /**
1544     * Make sure the caller has the MODIFY_PHONE_STATE permission.
1545     *
1546     * @throws SecurityException if the caller does not have the required permission
1547     */
1548    private void enforceModifyPermission() {
1549        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1550    }
1551
1552    /**
1553     * Make sure either system app or the caller has carrier privilege.
1554     *
1555     * @throws SecurityException if the caller does not have the required permission/privilege
1556     */
1557    private void enforceModifyPermissionOrCarrierPrivilege() {
1558        int permission = mApp.checkCallingOrSelfPermission(
1559                android.Manifest.permission.MODIFY_PHONE_STATE);
1560        if (permission == PackageManager.PERMISSION_GRANTED) {
1561            return;
1562        }
1563
1564        log("No modify permission, check carrier privilege next.");
1565        if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1566            loge("No Carrier Privilege.");
1567            throw new SecurityException("No modify permission or carrier privilege.");
1568        }
1569    }
1570
1571    /**
1572     * Make sure the caller has carrier privilege.
1573     *
1574     * @throws SecurityException if the caller does not have the required permission
1575     */
1576    private void enforceCarrierPrivilege() {
1577        if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1578            loge("No Carrier Privilege.");
1579            throw new SecurityException("No Carrier Privilege.");
1580        }
1581    }
1582
1583    /**
1584     * Make sure the caller has the CALL_PHONE permission.
1585     *
1586     * @throws SecurityException if the caller does not have the required permission
1587     */
1588    private void enforceCallPermission() {
1589        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1590    }
1591
1592    /**
1593     * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1594     *
1595     * @throws SecurityException if the caller does not have the required permission
1596     */
1597    private void enforcePrivilegedPhoneStatePermission() {
1598        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1599                null);
1600    }
1601
1602    private void enforceConnectivityInternalPermission() {
1603        mApp.enforceCallingOrSelfPermission(
1604                android.Manifest.permission.CONNECTIVITY_INTERNAL,
1605                "ConnectivityService");
1606    }
1607
1608    private String createTelUrl(String number) {
1609        if (TextUtils.isEmpty(number)) {
1610            return null;
1611        }
1612
1613        return "tel:" + number;
1614    }
1615
1616    private static void log(String msg) {
1617        Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1618    }
1619
1620    private static void logv(String msg) {
1621        Log.v(LOG_TAG, "[PhoneIntfMgr] " + msg);
1622    }
1623
1624    private static void loge(String msg) {
1625        Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1626    }
1627
1628    public int getActivePhoneType() {
1629        return getActivePhoneTypeForSubscriber(getDefaultSubscription());
1630    }
1631
1632    @Override
1633    public int getActivePhoneTypeForSubscriber(int subId) {
1634        final Phone phone = getPhone(subId);
1635        if (phone == null) {
1636            return PhoneConstants.PHONE_TYPE_NONE;
1637        } else {
1638            return getPhone(subId).getPhoneType();
1639        }
1640    }
1641
1642    /**
1643     * Returns the CDMA ERI icon index to display
1644     */
1645    public int getCdmaEriIconIndex() {
1646        return getCdmaEriIconIndexForSubscriber(getDefaultSubscription());
1647    }
1648
1649    @Override
1650    public int getCdmaEriIconIndexForSubscriber(int subId) {
1651        final Phone phone = getPhone(subId);
1652        if (phone != null) {
1653            return phone.getCdmaEriIconIndex();
1654        } else {
1655            return -1;
1656        }
1657    }
1658
1659    /**
1660     * Returns the CDMA ERI icon mode,
1661     * 0 - ON
1662     * 1 - FLASHING
1663     */
1664    public int getCdmaEriIconMode() {
1665        return getCdmaEriIconModeForSubscriber(getDefaultSubscription());
1666    }
1667
1668    @Override
1669    public int getCdmaEriIconModeForSubscriber(int subId) {
1670        final Phone phone = getPhone(subId);
1671        if (phone != null) {
1672            return phone.getCdmaEriIconMode();
1673        } else {
1674            return -1;
1675        }
1676    }
1677
1678    /**
1679     * Returns the CDMA ERI text,
1680     */
1681    public String getCdmaEriText() {
1682        return getCdmaEriTextForSubscriber(getDefaultSubscription());
1683    }
1684
1685    @Override
1686    public String getCdmaEriTextForSubscriber(int subId) {
1687        final Phone phone = getPhone(subId);
1688        if (phone != null) {
1689            return phone.getCdmaEriText();
1690        } else {
1691            return null;
1692        }
1693    }
1694
1695    /**
1696     * Returns the CDMA MDN.
1697     */
1698    @Override
1699    public String getCdmaMdn(int subId) {
1700        enforceModifyPermissionOrCarrierPrivilege();
1701        final Phone phone = getPhone(subId);
1702        if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA && phone != null) {
1703            return phone.getLine1Number();
1704        } else {
1705            return null;
1706        }
1707    }
1708
1709    /**
1710     * Returns the CDMA MIN.
1711     */
1712    @Override
1713    public String getCdmaMin(int subId) {
1714        enforceModifyPermissionOrCarrierPrivilege();
1715        final Phone phone = getPhone(subId);
1716        if (phone != null && phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1717            return phone.getCdmaMin();
1718        } else {
1719            return null;
1720        }
1721    }
1722
1723    /**
1724     * Returns true if CDMA provisioning needs to run.
1725     */
1726    public boolean needsOtaServiceProvisioning() {
1727        return mPhone.needsOtaServiceProvisioning();
1728    }
1729
1730    /**
1731     * Sets the voice mail number of a given subId.
1732     */
1733    @Override
1734    public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
1735        enforceCarrierPrivilege();
1736        Boolean success = (Boolean) sendRequest(CMD_SET_VOICEMAIL_NUMBER,
1737                new Pair<String, String>(alphaTag, number), new Integer(subId));
1738        return success;
1739    }
1740
1741    /**
1742     * Returns the unread count of voicemails
1743     */
1744    public int getVoiceMessageCount() {
1745        return getVoiceMessageCountForSubscriber(getDefaultSubscription());
1746    }
1747
1748    /**
1749     * Returns the unread count of voicemails for a subId
1750     */
1751    @Override
1752    public int getVoiceMessageCountForSubscriber( int subId) {
1753        final Phone phone = getPhone(subId);
1754        if (phone != null) {
1755            return phone.getVoiceMessageCount();
1756        } else {
1757            return 0;
1758        }
1759    }
1760
1761    /**
1762     * Returns the data network type
1763     *
1764     * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1765     */
1766    @Override
1767    public int getNetworkType() {
1768        return getNetworkTypeForSubscriber(getDefaultSubscription());
1769    }
1770
1771    /**
1772     * Returns the network type for a subId
1773     */
1774    @Override
1775    public int getNetworkTypeForSubscriber(int subId) {
1776        final Phone phone = getPhone(subId);
1777        if (phone != null) {
1778            return phone.getServiceState().getDataNetworkType();
1779        } else {
1780            return TelephonyManager.NETWORK_TYPE_UNKNOWN;
1781        }
1782    }
1783
1784    /**
1785     * Returns the data network type
1786     */
1787    @Override
1788    public int getDataNetworkType() {
1789        return getDataNetworkTypeForSubscriber(getDefaultSubscription());
1790    }
1791
1792    /**
1793     * Returns the data network type for a subId
1794     */
1795    @Override
1796    public int getDataNetworkTypeForSubscriber(int subId) {
1797        final Phone phone = getPhone(subId);
1798        if (phone != null) {
1799            return phone.getServiceState().getDataNetworkType();
1800        } else {
1801            return TelephonyManager.NETWORK_TYPE_UNKNOWN;
1802        }
1803    }
1804
1805    /**
1806     * Returns the data network type
1807     */
1808    @Override
1809    public int getVoiceNetworkType() {
1810        return getVoiceNetworkTypeForSubscriber(getDefaultSubscription());
1811    }
1812
1813    /**
1814     * Returns the Voice network type for a subId
1815     */
1816    @Override
1817    public int getVoiceNetworkTypeForSubscriber(int subId) {
1818        final Phone phone = getPhone(subId);
1819        if (phone != null) {
1820            return phone.getServiceState().getVoiceNetworkType();
1821        } else {
1822            return TelephonyManager.NETWORK_TYPE_UNKNOWN;
1823        }
1824    }
1825
1826    /**
1827     * @return true if a ICC card is present
1828     */
1829    public boolean hasIccCard() {
1830        // FIXME Make changes to pass defaultSimId of type int
1831        return hasIccCardUsingSlotId(mSubscriptionController.getSlotId(getDefaultSubscription()));
1832    }
1833
1834    /**
1835     * @return true if a ICC card is present for a slotId
1836     */
1837    @Override
1838    public boolean hasIccCardUsingSlotId(int slotId) {
1839        int subId[] = mSubscriptionController.getSubIdUsingSlotId(slotId);
1840        final Phone phone = getPhone(subId[0]);
1841        if (subId != null && phone != null) {
1842            return phone.getIccCard().hasIccCard();
1843        } else {
1844            return false;
1845        }
1846    }
1847
1848    /**
1849     * Return if the current radio is LTE on CDMA. This
1850     * is a tri-state return value as for a period of time
1851     * the mode may be unknown.
1852     *
1853     * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
1854     * or {@link Phone#LTE_ON_CDMA_TRUE}
1855     */
1856    public int getLteOnCdmaMode() {
1857        return getLteOnCdmaModeForSubscriber(getDefaultSubscription());
1858    }
1859
1860    @Override
1861    public int getLteOnCdmaModeForSubscriber(int subId) {
1862        final Phone phone = getPhone(subId);
1863        if (phone == null) {
1864            return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
1865        } else {
1866            return phone.getLteOnCdmaMode();
1867        }
1868    }
1869
1870    public void setPhone(Phone phone) {
1871        mPhone = phone;
1872    }
1873
1874    /**
1875     * {@hide}
1876     * Returns Default subId, 0 in the case of single standby.
1877     */
1878    private int getDefaultSubscription() {
1879        return mSubscriptionController.getDefaultSubId();
1880    }
1881
1882    private int getPreferredVoiceSubscription() {
1883        return mSubscriptionController.getDefaultVoiceSubId();
1884    }
1885
1886    /**
1887     * @see android.telephony.TelephonyManager.WifiCallingChoices
1888     */
1889    public int getWhenToMakeWifiCalls() {
1890        return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1891                Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
1892    }
1893
1894    /**
1895     * @see android.telephony.TelephonyManager.WifiCallingChoices
1896     */
1897    public void setWhenToMakeWifiCalls(int preference) {
1898        if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1899        Settings.System.putInt(mPhone.getContext().getContentResolver(),
1900                Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
1901    }
1902
1903    private static int getWhenToMakeWifiCallsDefaultPreference() {
1904        // TODO: Use a build property to choose this value.
1905        return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
1906    }
1907
1908    @Override
1909    public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
1910        enforceModifyPermissionOrCarrierPrivilege();
1911
1912        if (DBG) log("iccOpenLogicalChannel: " + AID);
1913        IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
1914            CMD_OPEN_CHANNEL, AID);
1915        if (DBG) log("iccOpenLogicalChannel: " + response);
1916        return response;
1917    }
1918
1919    @Override
1920    public boolean iccCloseLogicalChannel(int channel) {
1921        enforceModifyPermissionOrCarrierPrivilege();
1922
1923        if (DBG) log("iccCloseLogicalChannel: " + channel);
1924        if (channel < 0) {
1925          return false;
1926        }
1927        Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
1928        if (DBG) log("iccCloseLogicalChannel: " + success);
1929        return success;
1930    }
1931
1932    @Override
1933    public String iccTransmitApduLogicalChannel(int channel, int cla,
1934            int command, int p1, int p2, int p3, String data) {
1935        enforceModifyPermissionOrCarrierPrivilege();
1936
1937        if (DBG) {
1938            log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1939                    " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1940                    " data=" + data);
1941        }
1942
1943        if (channel < 0) {
1944            return "";
1945        }
1946
1947        IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
1948                new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1949        if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1950
1951        // Append the returned status code to the end of the response payload.
1952        String s = Integer.toHexString(
1953                (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1954        if (response.payload != null) {
1955            s = IccUtils.bytesToHexString(response.payload) + s;
1956        }
1957        return s;
1958    }
1959
1960    @Override
1961    public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
1962                int p3, String data) {
1963        enforceModifyPermissionOrCarrierPrivilege();
1964
1965        if (DBG) {
1966            log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
1967                    + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
1968        }
1969
1970        IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
1971                new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
1972        if (DBG) log("iccTransmitApduBasicChannel: " + response);
1973
1974        // Append the returned status code to the end of the response payload.
1975        String s = Integer.toHexString(
1976                (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1977        if (response.payload != null) {
1978            s = IccUtils.bytesToHexString(response.payload) + s;
1979        }
1980        return s;
1981    }
1982
1983    @Override
1984    public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
1985            String filePath) {
1986        enforceModifyPermissionOrCarrierPrivilege();
1987
1988        if (DBG) {
1989            log("Exchange SIM_IO " + fileID + ":" + command + " " +
1990                p1 + " " + p2 + " " + p3 + ":" + filePath);
1991        }
1992
1993        IccIoResult response =
1994            (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
1995                    new IccAPDUArgument(-1, fileID, command, p1, p2, p3, filePath));
1996
1997        if (DBG) {
1998          log("Exchange SIM_IO [R]" + response);
1999        }
2000
2001        byte[] result = null;
2002        int length = 2;
2003        if (response.payload != null) {
2004            length = 2 + response.payload.length;
2005            result = new byte[length];
2006            System.arraycopy(response.payload, 0, result, 0, response.payload.length);
2007        } else {
2008            result = new byte[length];
2009        }
2010
2011        result[length - 1] = (byte) response.sw2;
2012        result[length - 2] = (byte) response.sw1;
2013        return result;
2014    }
2015
2016    @Override
2017    public String sendEnvelopeWithStatus(String content) {
2018        enforceModifyPermissionOrCarrierPrivilege();
2019
2020        IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
2021        if (response.payload == null) {
2022          return "";
2023        }
2024
2025        // Append the returned status code to the end of the response payload.
2026        String s = Integer.toHexString(
2027                (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
2028        s = IccUtils.bytesToHexString(response.payload) + s;
2029        return s;
2030    }
2031
2032    /**
2033     * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
2034     * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
2035     *
2036     * @param itemID the ID of the item to read
2037     * @return the NV item as a String, or null on error.
2038     */
2039    @Override
2040    public String nvReadItem(int itemID) {
2041        enforceModifyPermissionOrCarrierPrivilege();
2042        if (DBG) log("nvReadItem: item " + itemID);
2043        String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
2044        if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
2045        return value;
2046    }
2047
2048    /**
2049     * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
2050     * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
2051     *
2052     * @param itemID the ID of the item to read
2053     * @param itemValue the value to write, as a String
2054     * @return true on success; false on any failure
2055     */
2056    @Override
2057    public boolean nvWriteItem(int itemID, String itemValue) {
2058        enforceModifyPermissionOrCarrierPrivilege();
2059        if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
2060        Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
2061                new Pair<Integer, String>(itemID, itemValue));
2062        if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
2063        return success;
2064    }
2065
2066    /**
2067     * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
2068     * Used for device configuration by some CDMA operators.
2069     *
2070     * @param preferredRoamingList byte array containing the new PRL
2071     * @return true on success; false on any failure
2072     */
2073    @Override
2074    public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
2075        enforceModifyPermissionOrCarrierPrivilege();
2076        if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
2077        Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
2078        if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
2079        return success;
2080    }
2081
2082    /**
2083     * Perform the specified type of NV config reset.
2084     * Used for device configuration by some CDMA operators.
2085     *
2086     * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
2087     * @return true on success; false on any failure
2088     */
2089    @Override
2090    public boolean nvResetConfig(int resetType) {
2091        enforceModifyPermissionOrCarrierPrivilege();
2092        if (DBG) log("nvResetConfig: type " + resetType);
2093        Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
2094        if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
2095        return success;
2096    }
2097
2098    /**
2099     * {@hide}
2100     * Returns Default sim, 0 in the case of single standby.
2101     */
2102    public int getDefaultSim() {
2103        //TODO Need to get it from Telephony Devcontroller
2104        return 0;
2105    }
2106
2107    public String[] getPcscfAddress(String apnType, String callingPackage) {
2108        if (!canReadPhoneState(callingPackage, "getPcscfAddress")) {
2109            return new String[0];
2110        }
2111
2112
2113        return mPhone.getPcscfAddress(apnType);
2114    }
2115
2116    public void setImsRegistrationState(boolean registered) {
2117        enforceModifyPermission();
2118        mPhone.setImsRegistrationState(registered);
2119    }
2120
2121    /**
2122     * Set the network selection mode to automatic.
2123     *
2124     */
2125    @Override
2126    public void setNetworkSelectionModeAutomatic(int subId) {
2127        enforceModifyPermissionOrCarrierPrivilege();
2128        if (DBG) log("setNetworkSelectionModeAutomatic: subId " + subId);
2129        sendRequest(CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC, null, subId);
2130    }
2131
2132    /**
2133     * Set the network selection mode to manual with the selected carrier.
2134     */
2135    @Override
2136    public boolean setNetworkSelectionModeManual(int subId, OperatorInfo operator) {
2137        enforceModifyPermissionOrCarrierPrivilege();
2138        if (DBG) log("setNetworkSelectionModeManual: subId:" + subId + " operator:" + operator);
2139        return (Boolean) sendRequest(CMD_SET_NETWORK_SELECTION_MODE_MANUAL, operator, subId);
2140    }
2141
2142    /**
2143     * Scans for available networks.
2144     */
2145    @Override
2146    public CellNetworkScanResult getCellNetworkScanResults(int subId) {
2147        enforceModifyPermissionOrCarrierPrivilege();
2148        if (DBG) log("getCellNetworkScanResults: subId " + subId);
2149        CellNetworkScanResult result = (CellNetworkScanResult) sendRequest(
2150                CMD_PERFORM_NETWORK_SCAN, null, subId);
2151        return result;
2152    }
2153
2154    /**
2155     * Get the calculated preferred network type.
2156     * Used for debugging incorrect network type.
2157     *
2158     * @return the preferred network type, defined in RILConstants.java.
2159     */
2160    @Override
2161    public int getCalculatedPreferredNetworkType(String callingPackage) {
2162        if (!canReadPhoneState(callingPackage, "getCalculatedPreferredNetworkType")) {
2163            return RILConstants.PREFERRED_NETWORK_MODE;
2164        }
2165
2166        return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext(), 0); // wink FIXME: need to get SubId from somewhere.
2167    }
2168
2169    /**
2170     * Get the preferred network type.
2171     * Used for device configuration by some CDMA operators.
2172     *
2173     * @return the preferred network type, defined in RILConstants.java.
2174     */
2175    @Override
2176    public int getPreferredNetworkType(int subId) {
2177        enforceModifyPermissionOrCarrierPrivilege();
2178        if (DBG) log("getPreferredNetworkType");
2179        int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null, subId);
2180        int networkType = (result != null ? result[0] : -1);
2181        if (DBG) log("getPreferredNetworkType: " + networkType);
2182        return networkType;
2183    }
2184
2185    /**
2186     * Set the preferred network type.
2187     * Used for device configuration by some CDMA operators.
2188     *
2189     * @param networkType the preferred network type, defined in RILConstants.java.
2190     * @return true on success; false on any failure.
2191     */
2192    @Override
2193    public boolean setPreferredNetworkType(int subId, int networkType) {
2194        enforceModifyPermissionOrCarrierPrivilege();
2195        if (DBG) log("setPreferredNetworkType: subId " + subId + " type " + networkType);
2196        Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);
2197        if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
2198        if (success) {
2199            Settings.Global.putInt(mPhone.getContext().getContentResolver(),
2200                    Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
2201        }
2202        return success;
2203    }
2204
2205    /**
2206     * Check TETHER_DUN_REQUIRED and TETHER_DUN_APN settings, net.tethering.noprovisioning
2207     * SystemProperty, and config_tether_apndata to decide whether DUN APN is required for
2208     * tethering.
2209     *
2210     * @return 0: Not required. 1: required. 2: Not set.
2211     * @hide
2212     */
2213    @Override
2214    public int getTetherApnRequired() {
2215        enforceModifyPermissionOrCarrierPrivilege();
2216        int dunRequired = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
2217                Settings.Global.TETHER_DUN_REQUIRED, 2);
2218        // If not set, check net.tethering.noprovisioning, TETHER_DUN_APN setting and
2219        // config_tether_apndata.
2220        if (dunRequired == 2 && mPhone.hasMatchedTetherApnSetting()) {
2221            dunRequired = 1;
2222        }
2223        return dunRequired;
2224    }
2225
2226    /**
2227     * Set mobile data enabled
2228     * Used by the user through settings etc to turn on/off mobile data
2229     *
2230     * @param enable {@code true} turn turn data on, else {@code false}
2231     */
2232    @Override
2233    public void setDataEnabled(int subId, boolean enable) {
2234        enforceModifyPermission();
2235        int phoneId = mSubscriptionController.getPhoneId(subId);
2236        log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
2237        Phone phone = PhoneFactory.getPhone(phoneId);
2238        if (phone != null) {
2239            log("setDataEnabled: subId=" + subId + " enable=" + enable);
2240            phone.setDataEnabled(enable);
2241        } else {
2242            loge("setDataEnabled: no phone for subId=" + subId);
2243        }
2244    }
2245
2246    /**
2247     * Get whether mobile data is enabled.
2248     *
2249     * Note that this used to be available from ConnectivityService, gated by
2250     * ACCESS_NETWORK_STATE permission, so this will accept either that or
2251     * our MODIFY_PHONE_STATE.
2252     *
2253     * @return {@code true} if data is enabled else {@code false}
2254     */
2255    @Override
2256    public boolean getDataEnabled(int subId) {
2257        try {
2258            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
2259                    null);
2260        } catch (Exception e) {
2261            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
2262                    null);
2263        }
2264        int phoneId = mSubscriptionController.getPhoneId(subId);
2265        log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
2266        Phone phone = PhoneFactory.getPhone(phoneId);
2267        if (phone != null) {
2268            boolean retVal = phone.getDataEnabled();
2269            log("getDataEnabled: subId=" + subId + " retVal=" + retVal);
2270            return retVal;
2271        } else {
2272            loge("getDataEnabled: no phone subId=" + subId + " retVal=false");
2273            return false;
2274        }
2275    }
2276
2277    @Override
2278    public int getCarrierPrivilegeStatus() {
2279        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
2280        if (card == null) {
2281            loge("getCarrierPrivilegeStatus: No UICC");
2282            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
2283        }
2284        return card.getCarrierPrivilegeStatusForCurrentTransaction(
2285                mPhone.getContext().getPackageManager());
2286    }
2287
2288    @Override
2289    public int checkCarrierPrivilegesForPackage(String pkgName) {
2290        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
2291        if (card == null) {
2292            loge("checkCarrierPrivilegesForPackage: No UICC");
2293            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
2294        }
2295        return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgName);
2296    }
2297
2298    @Override
2299    public int checkCarrierPrivilegesForPackageAnyPhone(String pkgName) {
2300        int result = TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
2301        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
2302            UiccCard card = UiccController.getInstance().getUiccCard(i);
2303            if (card == null) {
2304              // No UICC in that slot.
2305              continue;
2306            }
2307
2308            result = card.getCarrierPrivilegeStatus(
2309                mPhone.getContext().getPackageManager(), pkgName);
2310            if (result == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
2311                break;
2312            }
2313        }
2314
2315        return result;
2316    }
2317
2318    @Override
2319    public List<String> getCarrierPackageNamesForIntentAndPhone(Intent intent, int phoneId) {
2320        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
2321            loge("phoneId " + phoneId + " is not valid.");
2322            return null;
2323        }
2324        UiccCard card = UiccController.getInstance().getUiccCard(phoneId);
2325        if (card == null) {
2326            loge("getCarrierPackageNamesForIntent: No UICC");
2327            return null ;
2328        }
2329        return card.getCarrierPackageNamesForIntent(
2330                mPhone.getContext().getPackageManager(), intent);
2331    }
2332
2333    private String getIccId(int subId) {
2334        final Phone phone = getPhone(subId);
2335        UiccCard card = phone == null ? null : phone.getUiccCard();
2336        if (card == null) {
2337            loge("getIccId: No UICC");
2338            return null;
2339        }
2340        String iccId = card.getIccId();
2341        if (TextUtils.isEmpty(iccId)) {
2342            loge("getIccId: ICC ID is null or empty.");
2343            return null;
2344        }
2345        return iccId;
2346    }
2347
2348    @Override
2349    public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag,
2350            String number) {
2351        enforceCarrierPrivilege();
2352
2353        final String iccId = getIccId(subId);
2354        final Phone phone = getPhone(subId);
2355        if (phone == null) {
2356            return false;
2357        }
2358        final String subscriberId = phone.getSubscriberId();
2359
2360        if (DBG_MERGE) {
2361            Slog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
2362                    + subscriberId + " to " + number);
2363        }
2364
2365        if (TextUtils.isEmpty(iccId)) {
2366            return false;
2367        }
2368
2369        final SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
2370
2371        final String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
2372        if (alphaTag == null) {
2373            editor.remove(alphaTagPrefKey);
2374        } else {
2375            editor.putString(alphaTagPrefKey, alphaTag);
2376        }
2377
2378        // Record both the line number and IMSI for this ICCID, since we need to
2379        // track all merged IMSIs based on line number
2380        final String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2381        final String subscriberPrefKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
2382        if (number == null) {
2383            editor.remove(numberPrefKey);
2384            editor.remove(subscriberPrefKey);
2385        } else {
2386            editor.putString(numberPrefKey, number);
2387            editor.putString(subscriberPrefKey, subscriberId);
2388        }
2389
2390        editor.commit();
2391        return true;
2392    }
2393
2394    @Override
2395    public String getLine1NumberForDisplay(int subId, String callingPackage) {
2396        // This is open to apps with WRITE_SMS.
2397        if (!canReadPhoneNumber(callingPackage, "getLine1NumberForDisplay")) {
2398            return null;
2399        }
2400
2401        String iccId = getIccId(subId);
2402        if (iccId != null) {
2403            String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2404            return mTelephonySharedPreferences.getString(numberPrefKey, null);
2405        }
2406        return null;
2407    }
2408
2409    @Override
2410    public String getLine1AlphaTagForDisplay(int subId, String callingPackage) {
2411        if (!canReadPhoneState(callingPackage, "getLine1AlphaTagForDisplay")) {
2412            return null;
2413        }
2414
2415        String iccId = getIccId(subId);
2416        if (iccId != null) {
2417            String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
2418            return mTelephonySharedPreferences.getString(alphaTagPrefKey, null);
2419        }
2420        return null;
2421    }
2422
2423    @Override
2424    public String[] getMergedSubscriberIds(String callingPackage) {
2425        if (!canReadPhoneState(callingPackage, "getMergedSubscriberIds")) {
2426            return null;
2427        }
2428        final Context context = mPhone.getContext();
2429        final TelephonyManager tele = TelephonyManager.from(context);
2430        final SubscriptionManager sub = SubscriptionManager.from(context);
2431
2432        // Figure out what subscribers are currently active
2433        final ArraySet<String> activeSubscriberIds = new ArraySet<>();
2434        // Clear calling identity, when calling TelephonyManager, because callerUid must be
2435        // the process, where TelephonyManager was instantiated. Otherwise AppOps check will fail.
2436        final long identity  = Binder.clearCallingIdentity();
2437        try {
2438            final int[] subIds = sub.getActiveSubscriptionIdList();
2439            for (int subId : subIds) {
2440                activeSubscriberIds.add(tele.getSubscriberId(subId));
2441            }
2442        } finally {
2443            Binder.restoreCallingIdentity(identity);
2444        }
2445
2446        // First pass, find a number override for an active subscriber
2447        String mergeNumber = null;
2448        final Map<String, ?> prefs = mTelephonySharedPreferences.getAll();
2449        for (String key : prefs.keySet()) {
2450            if (key.startsWith(PREF_CARRIERS_SUBSCRIBER_PREFIX)) {
2451                final String subscriberId = (String) prefs.get(key);
2452                if (activeSubscriberIds.contains(subscriberId)) {
2453                    final String iccId = key.substring(PREF_CARRIERS_SUBSCRIBER_PREFIX.length());
2454                    final String numberKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2455                    mergeNumber = (String) prefs.get(numberKey);
2456                    if (DBG_MERGE) {
2457                        Slog.d(LOG_TAG, "Found line number " + mergeNumber
2458                                + " for active subscriber " + subscriberId);
2459                    }
2460                    if (!TextUtils.isEmpty(mergeNumber)) {
2461                        break;
2462                    }
2463                }
2464            }
2465        }
2466
2467        // Shortcut when no active merged subscribers
2468        if (TextUtils.isEmpty(mergeNumber)) {
2469            return null;
2470        }
2471
2472        // Second pass, find all subscribers under that line override
2473        final ArraySet<String> result = new ArraySet<>();
2474        for (String key : prefs.keySet()) {
2475            if (key.startsWith(PREF_CARRIERS_NUMBER_PREFIX)) {
2476                final String number = (String) prefs.get(key);
2477                if (mergeNumber.equals(number)) {
2478                    final String iccId = key.substring(PREF_CARRIERS_NUMBER_PREFIX.length());
2479                    final String subscriberKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
2480                    final String subscriberId = (String) prefs.get(subscriberKey);
2481                    if (!TextUtils.isEmpty(subscriberId)) {
2482                        result.add(subscriberId);
2483                    }
2484                }
2485            }
2486        }
2487
2488        final String[] resultArray = result.toArray(new String[result.size()]);
2489        Arrays.sort(resultArray);
2490        if (DBG_MERGE) {
2491            Slog.d(LOG_TAG, "Found subscribers " + Arrays.toString(resultArray) + " after merge");
2492        }
2493        return resultArray;
2494    }
2495
2496    @Override
2497    public boolean setOperatorBrandOverride(String brand) {
2498        enforceCarrierPrivilege();
2499        return mPhone.setOperatorBrandOverride(brand);
2500    }
2501
2502    @Override
2503    public boolean setRoamingOverride(List<String> gsmRoamingList,
2504            List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
2505            List<String> cdmaNonRoamingList) {
2506        enforceCarrierPrivilege();
2507        return mPhone.setRoamingOverride(gsmRoamingList, gsmNonRoamingList, cdmaRoamingList,
2508                cdmaNonRoamingList);
2509    }
2510
2511    @Override
2512    public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
2513        enforceModifyPermission();
2514
2515        int returnValue = 0;
2516        try {
2517            AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
2518            if(result.exception == null) {
2519                if (result.result != null) {
2520                    byte[] responseData = (byte[])(result.result);
2521                    if(responseData.length > oemResp.length) {
2522                        Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
2523                                responseData.length +  "bytes. Buffer Size is " +
2524                                oemResp.length + "bytes.");
2525                    }
2526                    System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
2527                    returnValue = responseData.length;
2528                }
2529            } else {
2530                CommandException ex = (CommandException) result.exception;
2531                returnValue = ex.getCommandError().ordinal();
2532                if(returnValue > 0) returnValue *= -1;
2533            }
2534        } catch (RuntimeException e) {
2535            Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
2536            returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
2537            if(returnValue > 0) returnValue *= -1;
2538        }
2539
2540        return returnValue;
2541    }
2542
2543    @Override
2544    public void setRadioCapability(RadioAccessFamily[] rafs) {
2545        try {
2546            ProxyController.getInstance().setRadioCapability(rafs);
2547        } catch (RuntimeException e) {
2548            Log.w(LOG_TAG, "setRadioCapability: Runtime Exception");
2549        }
2550    }
2551
2552    @Override
2553    public int getRadioAccessFamily(int phoneId) {
2554        return ProxyController.getInstance().getRadioAccessFamily(phoneId);
2555    }
2556
2557    @Override
2558    public void enableVideoCalling(boolean enable) {
2559        enforceModifyPermission();
2560        SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
2561        editor.putBoolean(PREF_ENABLE_VIDEO_CALLING, enable);
2562        editor.commit();
2563    }
2564
2565    @Override
2566    public boolean isVideoCallingEnabled(String callingPackage) {
2567        if (!canReadPhoneState(callingPackage, "isVideoCallingEnabled")) {
2568            return false;
2569        }
2570
2571        // Check the user preference and the  system-level IMS setting. Even if the user has
2572        // enabled video calling, if IMS is disabled we aren't able to support video calling.
2573        // In the long run, we may instead need to check if there exists a connection service
2574        // which can support video calling.
2575        return ImsManager.isVtEnabledByPlatform(mPhone.getContext())
2576                && ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())
2577                && mTelephonySharedPreferences.getBoolean(PREF_ENABLE_VIDEO_CALLING, true);
2578    }
2579
2580    @Override
2581    public boolean canChangeDtmfToneLength() {
2582        return mApp.getCarrierConfig().getBoolean(CarrierConfigManager.KEY_DTMF_TYPE_ENABLED_BOOL);
2583    }
2584
2585    @Override
2586    public boolean isWorldPhone() {
2587        return mApp.getCarrierConfig().getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL);
2588    }
2589
2590    @Override
2591    public boolean isTtyModeSupported() {
2592        TelecomManager telecomManager = TelecomManager.from(mPhone.getContext());
2593        TelephonyManager telephonyManager =
2594                (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
2595        return !telephonyManager.isMultiSimEnabled() && telecomManager.isTtySupported();
2596    }
2597
2598    @Override
2599    public boolean isHearingAidCompatibilitySupported() {
2600        return mPhone.getContext().getResources().getBoolean(R.bool.hac_enabled);
2601    }
2602
2603    /**
2604     * Returns the unique device ID of phone, for example, the IMEI for
2605     * GSM and the MEID for CDMA phones. Return null if device ID is not available.
2606     *
2607     * <p>Requires Permission:
2608     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
2609     */
2610    @Override
2611    public String getDeviceId(String callingPackage) {
2612        if (!canReadPhoneState(callingPackage, "getDeviceId")) {
2613            return null;
2614        }
2615
2616        final Phone phone = PhoneFactory.getPhone(0);
2617        if (phone != null) {
2618            return phone.getDeviceId();
2619        } else {
2620            return null;
2621        }
2622    }
2623
2624    /*
2625     * {@hide}
2626     * Returns the IMS Registration Status
2627     */
2628    @Override
2629    public boolean isImsRegistered() {
2630        return mPhone.isImsRegistered();
2631    }
2632
2633    @Override
2634    public int getSubIdForPhoneAccount(PhoneAccount phoneAccount) {
2635        return PhoneUtils.getSubIdForPhoneAccount(phoneAccount);
2636    }
2637
2638    /*
2639     * {@hide}
2640     * Returns the IMS Registration Status
2641     */
2642    public boolean isWifiCallingEnabled() {
2643        return mPhone.isWifiCallingEnabled();
2644    }
2645
2646    /*
2647     * {@hide}
2648     * Returns the IMS Registration Status
2649     */
2650    public boolean isVolteEnabled() {
2651        return mPhone.isVolteEnabled();
2652    }
2653
2654    private boolean canReadPhoneState(String callingPackage, String message) {
2655        boolean failReadPhoneState = false;
2656        try {
2657            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE,
2658                    message);
2659        } catch (SecurityException e) {
2660            failReadPhoneState = true;
2661        }
2662        if (failReadPhoneState) {
2663            mApp.enforceCallingOrSelfPermission(
2664                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
2665
2666            // SKIP checking for run-time permission since obtained PRIVILEDGED
2667            return true;
2668        }
2669
2670        if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
2671                callingPackage) != AppOpsManager.MODE_ALLOWED) {
2672            return false;
2673        }
2674
2675        return true;
2676    }
2677
2678    /**
2679     * Besides READ_PHONE_STATE, WRITE_SMS also allows apps to get phone numbers.
2680     */
2681    private boolean canReadPhoneNumber(String callingPackage, String message) {
2682        // Note canReadPhoneState() may throw, so we need to do the appops check first.
2683        return (mAppOps.noteOp(AppOpsManager.OP_WRITE_SMS,
2684                        Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED)
2685                || canReadPhoneState(callingPackage, message);
2686    }
2687
2688    @Override
2689    public void factoryReset(int subId) {
2690        enforceConnectivityInternalPermission();
2691        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
2692            return;
2693        }
2694
2695        final long identity = Binder.clearCallingIdentity();
2696        try {
2697            if (SubscriptionManager.isUsableSubIdValue(subId) && !mUserManager.hasUserRestriction(
2698                    UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
2699                // Enable data
2700                setDataEnabled(subId, true);
2701                // Set network selection mode to automatic
2702                setNetworkSelectionModeAutomatic(subId);
2703                // Set preferred mobile network type to the best available
2704                setPreferredNetworkType(subId, Phone.PREFERRED_NT_MODE);
2705                // Turn off roaming
2706                SubscriptionManager.from(mApp).setDataRoaming(0, subId);
2707            }
2708        } finally {
2709            Binder.restoreCallingIdentity(identity);
2710        }
2711    }
2712
2713    @Override
2714    public String getLocaleFromDefaultSim() {
2715        // We query all subscriptions instead of just the active ones, because
2716        // this might be called early on in the provisioning flow when the
2717        // subscriptions potentially aren't active yet.
2718        final List<SubscriptionInfo> slist = getAllSubscriptionInfoList();
2719        if (slist == null || slist.isEmpty()) {
2720            return null;
2721        }
2722
2723        // This function may be called very early, say, from the setup wizard, at
2724        // which point we won't have a default subscription set. If that's the case
2725        // we just choose the first, which will be valid in "most cases".
2726        final int defaultSubId = getDefaultSubscription();
2727        SubscriptionInfo info = null;
2728        if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2729            info = slist.get(0);
2730        } else {
2731            for (SubscriptionInfo item : slist) {
2732                if (item.getSubscriptionId() == defaultSubId) {
2733                    info = item;
2734                    break;
2735                }
2736            }
2737
2738            if (info == null) {
2739                return null;
2740            }
2741        }
2742
2743        // Try and fetch the locale from the carrier properties or from the SIM language
2744        // preferences (EF-PL and EF-LI)...
2745        final Phone defaultPhone = getPhone(info.getSubscriptionId());
2746        if (defaultPhone != null) {
2747            final Locale localeFromDefaultSim = defaultPhone.getLocaleFromSimAndCarrierPrefs();
2748            if (localeFromDefaultSim != null) {
2749                return localeFromDefaultSim.toLanguageTag();
2750            }
2751        }
2752
2753        // .. if that doesn't work, try and guess the language from the sim MCC.
2754        final int mcc = info.getMcc();
2755        final Locale locale = MccTable.getLocaleFromMcc(mPhone.getContext(), mcc);
2756        if (locale != null) {
2757            return locale.toLanguageTag();
2758        }
2759
2760        return null;
2761    }
2762
2763    private List<SubscriptionInfo> getAllSubscriptionInfoList() {
2764        final long identity = Binder.clearCallingIdentity();
2765        try {
2766            return mSubscriptionController.getAllSubInfoList(
2767                    mPhone.getContext().getOpPackageName());
2768        } finally {
2769            Binder.restoreCallingIdentity(identity);
2770        }
2771    }
2772
2773    private List<SubscriptionInfo> getActiveSubscriptionInfoList() {
2774        final long identity = Binder.clearCallingIdentity();
2775        try {
2776            return mSubscriptionController.getActiveSubscriptionInfoList(
2777                    mPhone.getContext().getOpPackageName());
2778        } finally {
2779            Binder.restoreCallingIdentity(identity);
2780        }
2781    }
2782
2783    /**
2784     * {@hide}
2785     * Returns the modem stats
2786     */
2787    @Override
2788    public ModemActivityInfo getModemActivityInfo() {
2789        return (ModemActivityInfo) sendRequest(CMD_GET_MODEM_ACTIVITY_INFO, null);
2790    }
2791}
2792