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