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