Home | History | Annotate | Download | only in phone
      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 
     17 package com.android.phone;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.AppOpsManager;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.SharedPreferences;
     25 import android.content.pm.PackageInfo;
     26 import android.content.pm.PackageManager;
     27 import android.content.pm.Signature;
     28 import android.net.ConnectivityManager;
     29 import android.net.Uri;
     30 import android.os.AsyncResult;
     31 import android.os.Binder;
     32 import android.os.Bundle;
     33 import android.os.Handler;
     34 import android.os.IBinder;
     35 import android.os.Looper;
     36 import android.os.Message;
     37 import android.os.Process;
     38 import android.os.RemoteException;
     39 import android.os.ServiceManager;
     40 import android.os.UserHandle;
     41 import android.preference.PreferenceManager;
     42 import android.provider.Settings;
     43 import android.telephony.CellInfo;
     44 import android.telephony.IccOpenLogicalChannelResponse;
     45 import android.telephony.NeighboringCellInfo;
     46 import android.telephony.ServiceState;
     47 import android.telephony.SubscriptionManager;
     48 import android.telephony.TelephonyManager;
     49 import android.text.TextUtils;
     50 import android.util.Log;
     51 import android.util.Pair;
     52 
     53 import com.android.internal.telephony.CallManager;
     54 import com.android.internal.telephony.CommandException;
     55 import com.android.internal.telephony.Connection;
     56 import com.android.internal.telephony.DefaultPhoneNotifier;
     57 import com.android.internal.telephony.ITelephony;
     58 import com.android.internal.telephony.IccCard;
     59 import com.android.internal.telephony.Phone;
     60 import com.android.internal.telephony.PhoneFactory;
     61 import com.android.internal.telephony.CallManager;
     62 import com.android.internal.telephony.CommandException;
     63 import com.android.internal.telephony.PhoneConstants;
     64 import com.android.internal.telephony.dataconnection.DctController;
     65 import com.android.internal.telephony.uicc.AdnRecord;
     66 import com.android.internal.telephony.uicc.IccIoResult;
     67 import com.android.internal.telephony.uicc.IccUtils;
     68 import com.android.internal.telephony.uicc.UiccCard;
     69 import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules;
     70 import com.android.internal.telephony.uicc.UiccController;
     71 import com.android.internal.util.HexDump;
     72 
     73 import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
     74 
     75 import java.util.ArrayList;
     76 import java.util.HashMap;
     77 import java.util.HashSet;
     78 import java.util.Iterator;
     79 import java.util.List;
     80 import java.util.Map;
     81 import java.util.Set;
     82 
     83 /**
     84  * Implementation of the ITelephony interface.
     85  */
     86 public 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