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