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