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