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