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