Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2015 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.internal.telephony;
     18 
     19 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
     20 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
     21 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
     22 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
     23 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
     24 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
     25 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
     26 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
     27 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
     28 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
     29 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
     30 
     31 import android.annotation.NonNull;
     32 import android.annotation.Nullable;
     33 import android.app.ActivityManager;
     34 import android.content.BroadcastReceiver;
     35 import android.content.ContentValues;
     36 import android.content.Context;
     37 import android.content.Intent;
     38 import android.content.IntentFilter;
     39 import android.content.SharedPreferences;
     40 import android.database.SQLException;
     41 import android.net.Uri;
     42 import android.os.AsyncResult;
     43 import android.os.Bundle;
     44 import android.os.Handler;
     45 import android.os.Message;
     46 import android.os.PersistableBundle;
     47 import android.os.PowerManager;
     48 import android.os.Registrant;
     49 import android.os.RegistrantList;
     50 import android.os.ResultReceiver;
     51 import android.os.SystemProperties;
     52 import android.os.UserHandle;
     53 import android.os.WorkSource;
     54 import android.preference.PreferenceManager;
     55 import android.provider.Settings;
     56 import android.provider.Telephony;
     57 import android.telecom.VideoProfile;
     58 import android.telephony.CarrierConfigManager;
     59 import android.telephony.CellLocation;
     60 import android.telephony.ImsiEncryptionInfo;
     61 import android.telephony.NetworkScanRequest;
     62 import android.telephony.PhoneNumberUtils;
     63 import android.telephony.Rlog;
     64 import android.telephony.ServiceState;
     65 import android.telephony.SubscriptionInfo;
     66 import android.telephony.SubscriptionManager;
     67 import android.telephony.TelephonyManager;
     68 import android.telephony.UssdResponse;
     69 import android.telephony.cdma.CdmaCellLocation;
     70 import android.text.TextUtils;
     71 import android.util.Log;
     72 
     73 import com.android.ims.ImsManager;
     74 import com.android.internal.annotations.VisibleForTesting;
     75 import com.android.internal.telephony.cdma.CdmaMmiCode;
     76 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
     77 import com.android.internal.telephony.cdma.EriManager;
     78 import com.android.internal.telephony.gsm.GsmMmiCode;
     79 import com.android.internal.telephony.gsm.SuppServiceNotification;
     80 import com.android.internal.telephony.test.SimulatedRadioControl;
     81 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
     82 import com.android.internal.telephony.uicc.IccException;
     83 import com.android.internal.telephony.uicc.IccRecords;
     84 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
     85 import com.android.internal.telephony.uicc.IsimRecords;
     86 import com.android.internal.telephony.uicc.IsimUiccRecords;
     87 import com.android.internal.telephony.uicc.RuimRecords;
     88 import com.android.internal.telephony.uicc.SIMRecords;
     89 import com.android.internal.telephony.uicc.UiccCard;
     90 import com.android.internal.telephony.uicc.UiccCardApplication;
     91 import com.android.internal.telephony.uicc.UiccController;
     92 import com.android.internal.telephony.uicc.UiccProfile;
     93 import com.android.internal.telephony.uicc.UiccSlot;
     94 
     95 import java.io.FileDescriptor;
     96 import java.io.PrintWriter;
     97 import java.util.ArrayList;
     98 import java.util.List;
     99 import java.util.regex.Matcher;
    100 import java.util.regex.Pattern;
    101 
    102 /**
    103  * {@hide}
    104  */
    105 public class GsmCdmaPhone extends Phone {
    106     // NOTE that LOG_TAG here is "GsmCdma", which means that log messages
    107     // from this file will go into the radio log rather than the main
    108     // log.  (Use "adb logcat -b radio" to see them.)
    109     public static final String LOG_TAG = "GsmCdmaPhone";
    110     private static final boolean DBG = true;
    111     private static final boolean VDBG = false; /* STOPSHIP if true */
    112 
    113     /** Required magnitude change between unsolicited SignalStrength reports. */
    114     private static final int REPORTING_HYSTERESIS_DB = 2;
    115     /** Required throughput change between unsolicited LinkCapacityEstimate reports. */
    116     private static final int REPORTING_HYSTERESIS_KBPS = 50;
    117     /** Minimum time between unsolicited SignalStrength and LinkCapacityEstimate reports. */
    118     private static final int REPORTING_HYSTERESIS_MILLIS = 3000;
    119 
    120     //GSM
    121     // Key used to read/write voice mail number
    122     private static final String VM_NUMBER = "vm_number_key";
    123     // Key used to read/write the SIM IMSI used for storing the voice mail
    124     private static final String VM_SIM_IMSI = "vm_sim_imsi_key";
    125     /** List of Registrants to receive Supplementary Service Notifications. */
    126     private RegistrantList mSsnRegistrants = new RegistrantList();
    127 
    128     //CDMA
    129     // Default Emergency Callback Mode exit timer
    130     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
    131     private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
    132     public static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
    133     public static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
    134     private CdmaSubscriptionSourceManager mCdmaSSM;
    135     public int mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
    136     public EriManager mEriManager;
    137     private PowerManager.WakeLock mWakeLock;
    138     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
    139     private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
    140     // mEcmExitRespRegistrant is informed after the phone has been exited
    141     private Registrant mEcmExitRespRegistrant;
    142     private String mEsn;
    143     private String mMeid;
    144     // string to define how the carrier specifies its own ota sp number
    145     private String mCarrierOtaSpNumSchema;
    146 
    147     // A runnable which is used to automatically exit from Ecm after a period of time.
    148     private Runnable mExitEcmRunnable = new Runnable() {
    149         @Override
    150         public void run() {
    151             exitEmergencyCallbackMode();
    152         }
    153     };
    154     public static final String PROPERTY_CDMA_HOME_OPERATOR_NUMERIC =
    155             "ro.cdma.home.operator.numeric";
    156 
    157     //CDMALTE
    158     /** PHONE_TYPE_CDMA_LTE in addition to RuimRecords needs access to SIMRecords and
    159      * IsimUiccRecords
    160      */
    161     private SIMRecords mSimRecords;
    162 
    163     //Common
    164     // Instance Variables
    165     private IsimUiccRecords mIsimUiccRecords;
    166     public GsmCdmaCallTracker mCT;
    167     public ServiceStateTracker mSST;
    168     private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
    169     private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
    170     // Used for identify the carrier of current subscription
    171     private CarrierIdentifier mCarrerIdentifier;
    172 
    173     private int mPrecisePhoneType;
    174 
    175     // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
    176     private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
    177 
    178     private String mImei;
    179     private String mImeiSv;
    180     private String mVmNumber;
    181 
    182     // Create Cfu (Call forward unconditional) so that dialing number &
    183     // mOnComplete (Message object passed by client) can be packed &
    184     // given as a single Cfu object as user data to RIL.
    185     private static class Cfu {
    186         final String mSetCfNumber;
    187         final Message mOnComplete;
    188 
    189         Cfu(String cfNumber, Message onComplete) {
    190             mSetCfNumber = cfNumber;
    191             mOnComplete = onComplete;
    192         }
    193     }
    194 
    195     private IccSmsInterfaceManager mIccSmsInterfaceManager;
    196 
    197     private boolean mResetModemOnRadioTechnologyChange = false;
    198 
    199     private int mRilVersion;
    200     private boolean mBroadcastEmergencyCallStateChanges = false;
    201     private CarrierKeyDownloadManager mCDM;
    202     private CarrierInfoManager mCIM;
    203 
    204     // Constructors
    205 
    206     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId,
    207                         int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) {
    208         this(context, ci, notifier, false, phoneId, precisePhoneType, telephonyComponentFactory);
    209     }
    210 
    211     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
    212                         boolean unitTestMode, int phoneId, int precisePhoneType,
    213                         TelephonyComponentFactory telephonyComponentFactory) {
    214         super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA",
    215                 notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);
    216 
    217         // phone type needs to be set before other initialization as other objects rely on it
    218         mPrecisePhoneType = precisePhoneType;
    219         initOnce(ci);
    220         initRatSpecific(precisePhoneType);
    221         // CarrierSignalAgent uses CarrierActionAgent in construction so it needs to be created
    222         // after CarrierActionAgent.
    223         mCarrierActionAgent = mTelephonyComponentFactory.makeCarrierActionAgent(this);
    224         mCarrierSignalAgent = mTelephonyComponentFactory.makeCarrierSignalAgent(this);
    225         mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
    226         // DcTracker uses SST so needs to be created after it is instantiated
    227         mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
    228         mCarrerIdentifier = mTelephonyComponentFactory.makeCarrierIdentifier(this);
    229 
    230         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
    231         mDeviceStateMonitor = mTelephonyComponentFactory.makeDeviceStateMonitor(this);
    232         logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
    233     }
    234 
    235     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    236         @Override
    237         public void onReceive(Context context, Intent intent) {
    238             Rlog.d(LOG_TAG, "mBroadcastReceiver: action " + intent.getAction());
    239             if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
    240                 sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED));
    241             }
    242         }
    243     };
    244 
    245     private void initOnce(CommandsInterface ci) {
    246         if (ci instanceof SimulatedRadioControl) {
    247             mSimulatedRadioControl = (SimulatedRadioControl) ci;
    248         }
    249 
    250         mCT = mTelephonyComponentFactory.makeGsmCdmaCallTracker(this);
    251         mIccPhoneBookIntManager = mTelephonyComponentFactory.makeIccPhoneBookInterfaceManager(this);
    252         PowerManager pm
    253                 = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    254         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
    255         mIccSmsInterfaceManager = mTelephonyComponentFactory.makeIccSmsInterfaceManager(this);
    256 
    257         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
    258         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
    259         mCi.registerForOn(this, EVENT_RADIO_ON, null);
    260         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
    261 
    262         //GSM
    263         mCi.setOnUSSD(this, EVENT_USSD, null);
    264         mCi.setOnSs(this, EVENT_SS, null);
    265 
    266         //CDMA
    267         mCdmaSSM = mTelephonyComponentFactory.getCdmaSubscriptionSourceManagerInstance(mContext,
    268                 mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
    269         mEriManager = mTelephonyComponentFactory.makeEriManager(this, mContext,
    270                 EriManager.ERI_FROM_XML);
    271         mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
    272         mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE,
    273                 null);
    274         mCi.registerForModemReset(this, EVENT_MODEM_RESET, null);
    275         // get the string that specifies the carrier OTA Sp number
    276         mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone(
    277                 getPhoneId(), "");
    278 
    279         mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
    280                 TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
    281 
    282         mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
    283         mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
    284         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
    285                 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
    286         mCDM = new CarrierKeyDownloadManager(this);
    287         mCIM = new CarrierInfoManager();
    288     }
    289 
    290     private void initRatSpecific(int precisePhoneType) {
    291         mPendingMMIs.clear();
    292         mIccPhoneBookIntManager.updateIccRecords(null);
    293         mEsn = null;
    294         mMeid = null;
    295 
    296         mPrecisePhoneType = precisePhoneType;
    297         logd("Precise phone type " + mPrecisePhoneType);
    298 
    299         TelephonyManager tm = TelephonyManager.from(mContext);
    300         UiccProfile uiccProfile = getUiccProfile();
    301         if (isPhoneTypeGsm()) {
    302             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
    303             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM);
    304             if (uiccProfile != null) {
    305                 uiccProfile.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
    306             }
    307         } else {
    308             mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
    309             // This is needed to handle phone process crashes
    310             mIsPhoneInEcmState = getInEcmMode();
    311             if (mIsPhoneInEcmState) {
    312                 // Send a message which will invoke handleExitEmergencyCallbackMode
    313                 mCi.exitEmergencyCallbackMode(
    314                         obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
    315             }
    316 
    317             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
    318             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_CDMA);
    319             if (uiccProfile != null) {
    320                 uiccProfile.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
    321             }
    322             // Sets operator properties by retrieving from build-time system property
    323             String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
    324             String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
    325             logd("init: operatorAlpha='" + operatorAlpha
    326                     + "' operatorNumeric='" + operatorNumeric + "'");
    327             if (!TextUtils.isEmpty(operatorAlpha)) {
    328                 logd("init: set 'gsm.sim.operator.alpha' to operator='" + operatorAlpha + "'");
    329                 tm.setSimOperatorNameForPhone(mPhoneId, operatorAlpha);
    330             }
    331             if (!TextUtils.isEmpty(operatorNumeric)) {
    332                 logd("init: set 'gsm.sim.operator.numeric' to operator='" + operatorNumeric +
    333                         "'");
    334                 logd("update icc_operator_numeric=" + operatorNumeric);
    335                 tm.setSimOperatorNumericForPhone(mPhoneId, operatorNumeric);
    336 
    337                 SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId());
    338                 // Sets iso country property by retrieving from build-time system property
    339                 setIsoCountryProperty(operatorNumeric);
    340                 // Updates MCC MNC device configuration information
    341                 logd("update mccmnc=" + operatorNumeric);
    342                 MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
    343             }
    344 
    345             // Sets current entry in the telephony carrier table
    346             updateCurrentCarrierInProvider(operatorNumeric);
    347         }
    348     }
    349 
    350     //CDMA
    351     /**
    352      * Sets PROPERTY_ICC_OPERATOR_ISO_COUNTRY property
    353      *
    354      */
    355     private void setIsoCountryProperty(String operatorNumeric) {
    356         TelephonyManager tm = TelephonyManager.from(mContext);
    357         if (TextUtils.isEmpty(operatorNumeric)) {
    358             logd("setIsoCountryProperty: clear 'gsm.sim.operator.iso-country'");
    359             tm.setSimCountryIsoForPhone(mPhoneId, "");
    360         } else {
    361             String iso = "";
    362             try {
    363                 iso = MccTable.countryCodeForMcc(Integer.parseInt(
    364                         operatorNumeric.substring(0,3)));
    365             } catch (NumberFormatException ex) {
    366                 Rlog.e(LOG_TAG, "setIsoCountryProperty: countryCodeForMcc error", ex);
    367             } catch (StringIndexOutOfBoundsException ex) {
    368                 Rlog.e(LOG_TAG, "setIsoCountryProperty: countryCodeForMcc error", ex);
    369             }
    370 
    371             logd("setIsoCountryProperty: set 'gsm.sim.operator.iso-country' to iso=" + iso);
    372             tm.setSimCountryIsoForPhone(mPhoneId, iso);
    373         }
    374     }
    375 
    376     public boolean isPhoneTypeGsm() {
    377         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM;
    378     }
    379 
    380     public boolean isPhoneTypeCdma() {
    381         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA;
    382     }
    383 
    384     public boolean isPhoneTypeCdmaLte() {
    385         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA_LTE;
    386     }
    387 
    388     private void switchPhoneType(int precisePhoneType) {
    389         removeCallbacks(mExitEcmRunnable);
    390 
    391         initRatSpecific(precisePhoneType);
    392 
    393         mSST.updatePhoneType();
    394         setPhoneName(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA");
    395         onUpdateIccAvailability();
    396         mCT.updatePhoneType();
    397 
    398         CommandsInterface.RadioState radioState = mCi.getRadioState();
    399         if (radioState.isAvailable()) {
    400             handleRadioAvailable();
    401             if (radioState.isOn()) {
    402                 handleRadioOn();
    403             }
    404         }
    405         if (!radioState.isAvailable() || !radioState.isOn()) {
    406             handleRadioOffOrNotAvailable();
    407         }
    408     }
    409 
    410     @Override
    411     protected void finalize() {
    412         if(DBG) logd("GsmCdmaPhone finalized");
    413         if (mWakeLock != null && mWakeLock.isHeld()) {
    414             Rlog.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
    415             mWakeLock.release();
    416         }
    417     }
    418 
    419     @Override
    420     public ServiceState getServiceState() {
    421         if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) {
    422             if (mImsPhone != null) {
    423                 return ServiceState.mergeServiceStates(
    424                         (mSST == null) ? new ServiceState() : mSST.mSS,
    425                         mImsPhone.getServiceState());
    426             }
    427         }
    428 
    429         if (mSST != null) {
    430             return mSST.mSS;
    431         } else {
    432             // avoid potential NPE in EmergencyCallHelper during Phone switch
    433             return new ServiceState();
    434         }
    435     }
    436 
    437     @Override
    438     public CellLocation getCellLocation(WorkSource workSource) {
    439         if (isPhoneTypeGsm()) {
    440             return mSST.getCellLocation(workSource);
    441         } else {
    442             CdmaCellLocation loc = (CdmaCellLocation)mSST.mCellLoc;
    443 
    444             int mode = Settings.Secure.getInt(getContext().getContentResolver(),
    445                     Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
    446             if (mode == Settings.Secure.LOCATION_MODE_OFF) {
    447                 // clear lat/long values for location privacy
    448                 CdmaCellLocation privateLoc = new CdmaCellLocation();
    449                 privateLoc.setCellLocationData(loc.getBaseStationId(),
    450                         CdmaCellLocation.INVALID_LAT_LONG,
    451                         CdmaCellLocation.INVALID_LAT_LONG,
    452                         loc.getSystemId(), loc.getNetworkId());
    453                 loc = privateLoc;
    454             }
    455             return loc;
    456         }
    457     }
    458 
    459     @Override
    460     public PhoneConstants.State getState() {
    461         if (mImsPhone != null) {
    462             PhoneConstants.State imsState = mImsPhone.getState();
    463             if (imsState != PhoneConstants.State.IDLE) {
    464                 return imsState;
    465             }
    466         }
    467 
    468         return mCT.mState;
    469     }
    470 
    471     @Override
    472     public int getPhoneType() {
    473         if (mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM) {
    474             return PhoneConstants.PHONE_TYPE_GSM;
    475         } else {
    476             return PhoneConstants.PHONE_TYPE_CDMA;
    477         }
    478     }
    479 
    480     @Override
    481     public ServiceStateTracker getServiceStateTracker() {
    482         return mSST;
    483     }
    484 
    485     @Override
    486     public CallTracker getCallTracker() {
    487         return mCT;
    488     }
    489 
    490     @Override
    491     public void updateVoiceMail() {
    492         if (isPhoneTypeGsm()) {
    493             int countVoiceMessages = 0;
    494             IccRecords r = mIccRecords.get();
    495             if (r != null) {
    496                 // get voice mail count from SIM
    497                 countVoiceMessages = r.getVoiceMessageCount();
    498             }
    499             if (countVoiceMessages == IccRecords.DEFAULT_VOICE_MESSAGE_COUNT) {
    500                 countVoiceMessages = getStoredVoiceMessageCount();
    501             }
    502             logd("updateVoiceMail countVoiceMessages = " + countVoiceMessages
    503                     + " subId " + getSubId());
    504             setVoiceMessageCount(countVoiceMessages);
    505         } else {
    506             setVoiceMessageCount(getStoredVoiceMessageCount());
    507         }
    508     }
    509 
    510     @Override
    511     public List<? extends MmiCode>
    512     getPendingMmiCodes() {
    513         return mPendingMMIs;
    514     }
    515 
    516     @Override
    517     public PhoneConstants.DataState getDataConnectionState(String apnType) {
    518         PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
    519 
    520         if (mSST == null) {
    521             // Radio Technology Change is ongoning, dispose() and removeReferences() have
    522             // already been called
    523 
    524             ret = PhoneConstants.DataState.DISCONNECTED;
    525         } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE
    526                 && (isPhoneTypeCdma() || isPhoneTypeCdmaLte() ||
    527                 (isPhoneTypeGsm() && !apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY)))) {
    528             // If we're out of service, open TCP sockets may still work
    529             // but no data will flow
    530 
    531             // Emergency APN is available even in Out Of Service
    532             // Pass the actual State of EPDN
    533 
    534             ret = PhoneConstants.DataState.DISCONNECTED;
    535         } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
    536             switch (mDcTracker.getState(apnType)) {
    537                 case CONNECTED:
    538                 case DISCONNECTING:
    539                     if ( mCT.mState != PhoneConstants.State.IDLE
    540                             && !mSST.isConcurrentVoiceAndDataAllowed()) {
    541                         ret = PhoneConstants.DataState.SUSPENDED;
    542                     } else {
    543                         ret = PhoneConstants.DataState.CONNECTED;
    544                     }
    545                     break;
    546                 case CONNECTING:
    547                     ret = PhoneConstants.DataState.CONNECTING;
    548                     break;
    549                 default:
    550                     ret = PhoneConstants.DataState.DISCONNECTED;
    551             }
    552         }
    553 
    554         logd("getDataConnectionState apnType=" + apnType + " ret=" + ret);
    555         return ret;
    556     }
    557 
    558     @Override
    559     public DataActivityState getDataActivityState() {
    560         DataActivityState ret = DataActivityState.NONE;
    561 
    562         if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
    563             switch (mDcTracker.getActivity()) {
    564                 case DATAIN:
    565                     ret = DataActivityState.DATAIN;
    566                 break;
    567 
    568                 case DATAOUT:
    569                     ret = DataActivityState.DATAOUT;
    570                 break;
    571 
    572                 case DATAINANDOUT:
    573                     ret = DataActivityState.DATAINANDOUT;
    574                 break;
    575 
    576                 case DORMANT:
    577                     ret = DataActivityState.DORMANT;
    578                 break;
    579 
    580                 default:
    581                     ret = DataActivityState.NONE;
    582                 break;
    583             }
    584         }
    585 
    586         return ret;
    587     }
    588 
    589     /**
    590      * Notify any interested party of a Phone state change
    591      * {@link com.android.internal.telephony.PhoneConstants.State}
    592      */
    593     public void notifyPhoneStateChanged() {
    594         mNotifier.notifyPhoneState(this);
    595     }
    596 
    597     /**
    598      * Notify registrants of a change in the call state. This notifies changes in
    599      * {@link com.android.internal.telephony.Call.State}. Use this when changes
    600      * in the precise call state are needed, else use notifyPhoneStateChanged.
    601      */
    602     public void notifyPreciseCallStateChanged() {
    603         /* we'd love it if this was package-scoped*/
    604         super.notifyPreciseCallStateChangedP();
    605     }
    606 
    607     public void notifyNewRingingConnection(Connection c) {
    608         super.notifyNewRingingConnectionP(c);
    609     }
    610 
    611     public void notifyDisconnect(Connection cn) {
    612         mDisconnectRegistrants.notifyResult(cn);
    613 
    614         mNotifier.notifyDisconnectCause(cn.getDisconnectCause(), cn.getPreciseDisconnectCause());
    615     }
    616 
    617     public void notifyUnknownConnection(Connection cn) {
    618         super.notifyUnknownConnectionP(cn);
    619     }
    620 
    621     @Override
    622     public boolean isInEmergencyCall() {
    623         if (isPhoneTypeGsm()) {
    624             return false;
    625         } else {
    626             return mCT.isInEmergencyCall();
    627         }
    628     }
    629 
    630     @Override
    631     protected void setIsInEmergencyCall() {
    632         if (!isPhoneTypeGsm()) {
    633             mCT.setIsInEmergencyCall();
    634         }
    635     }
    636 
    637     //CDMA
    638     private void sendEmergencyCallbackModeChange(){
    639         //Send an Intent
    640         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
    641         intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, isInEcm());
    642         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
    643         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
    644         if (DBG) logd("sendEmergencyCallbackModeChange");
    645     }
    646 
    647     @Override
    648     public void sendEmergencyCallStateChange(boolean callActive) {
    649         if (mBroadcastEmergencyCallStateChanges) {
    650             Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
    651             intent.putExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, callActive);
    652             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
    653             ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
    654             if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: callActive " + callActive);
    655         }
    656     }
    657 
    658     @Override
    659     public void setBroadcastEmergencyCallStateChanges(boolean broadcast) {
    660         mBroadcastEmergencyCallStateChanges = broadcast;
    661     }
    662 
    663     public void notifySuppServiceFailed(SuppService code) {
    664         mSuppServiceFailedRegistrants.notifyResult(code);
    665     }
    666 
    667     public void notifyServiceStateChanged(ServiceState ss) {
    668         super.notifyServiceStateChangedP(ss);
    669     }
    670 
    671     public void notifyLocationChanged() {
    672         mNotifier.notifyCellLocation(this);
    673     }
    674 
    675     @Override
    676     public void notifyCallForwardingIndicator() {
    677         mNotifier.notifyCallForwardingChanged(this);
    678     }
    679 
    680     @Override
    681     public void registerForSuppServiceNotification(
    682             Handler h, int what, Object obj) {
    683         mSsnRegistrants.addUnique(h, what, obj);
    684         if (mSsnRegistrants.size() == 1) mCi.setSuppServiceNotifications(true, null);
    685     }
    686 
    687     @Override
    688     public void unregisterForSuppServiceNotification(Handler h) {
    689         mSsnRegistrants.remove(h);
    690         if (mSsnRegistrants.size() == 0) mCi.setSuppServiceNotifications(false, null);
    691     }
    692 
    693     @Override
    694     public void registerForSimRecordsLoaded(Handler h, int what, Object obj) {
    695         mSimRecordsLoadedRegistrants.addUnique(h, what, obj);
    696     }
    697 
    698     @Override
    699     public void unregisterForSimRecordsLoaded(Handler h) {
    700         mSimRecordsLoadedRegistrants.remove(h);
    701     }
    702 
    703     @Override
    704     public void acceptCall(int videoState) throws CallStateException {
    705         Phone imsPhone = mImsPhone;
    706         if ( imsPhone != null && imsPhone.getRingingCall().isRinging() ) {
    707             imsPhone.acceptCall(videoState);
    708         } else {
    709             mCT.acceptCall();
    710         }
    711     }
    712 
    713     @Override
    714     public void rejectCall() throws CallStateException {
    715         mCT.rejectCall();
    716     }
    717 
    718     @Override
    719     public void switchHoldingAndActive() throws CallStateException {
    720         mCT.switchWaitingOrHoldingAndActive();
    721     }
    722 
    723     @Override
    724     public String getIccSerialNumber() {
    725         IccRecords r = mIccRecords.get();
    726         if (!isPhoneTypeGsm() && r == null) {
    727             // to get ICCID form SIMRecords because it is on MF.
    728             r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP);
    729         }
    730         return (r != null) ? r.getIccId() : null;
    731     }
    732 
    733     @Override
    734     public String getFullIccSerialNumber() {
    735         IccRecords r = mIccRecords.get();
    736         if (!isPhoneTypeGsm() && r == null) {
    737             // to get ICCID form SIMRecords because it is on MF.
    738             r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP);
    739         }
    740         return (r != null) ? r.getFullIccId() : null;
    741     }
    742 
    743     @Override
    744     public boolean canConference() {
    745         if (mImsPhone != null && mImsPhone.canConference()) {
    746             return true;
    747         }
    748         if (isPhoneTypeGsm()) {
    749             return mCT.canConference();
    750         } else {
    751             loge("canConference: not possible in CDMA");
    752             return false;
    753         }
    754     }
    755 
    756     @Override
    757     public void conference() {
    758         if (mImsPhone != null && mImsPhone.canConference()) {
    759             logd("conference() - delegated to IMS phone");
    760             try {
    761                 mImsPhone.conference();
    762             } catch (CallStateException e) {
    763                 loge(e.toString());
    764             }
    765             return;
    766         }
    767         if (isPhoneTypeGsm()) {
    768             mCT.conference();
    769         } else {
    770             // three way calls in CDMA will be handled by feature codes
    771             loge("conference: not possible in CDMA");
    772         }
    773     }
    774 
    775     @Override
    776     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
    777         if (isPhoneTypeGsm()) {
    778             loge("enableEnhancedVoicePrivacy: not expected on GSM");
    779         } else {
    780             mCi.setPreferredVoicePrivacy(enable, onComplete);
    781         }
    782     }
    783 
    784     @Override
    785     public void getEnhancedVoicePrivacy(Message onComplete) {
    786         if (isPhoneTypeGsm()) {
    787             loge("getEnhancedVoicePrivacy: not expected on GSM");
    788         } else {
    789             mCi.getPreferredVoicePrivacy(onComplete);
    790         }
    791     }
    792 
    793     @Override
    794     public void clearDisconnected() {
    795         mCT.clearDisconnected();
    796     }
    797 
    798     @Override
    799     public boolean canTransfer() {
    800         if (isPhoneTypeGsm()) {
    801             return mCT.canTransfer();
    802         } else {
    803             loge("canTransfer: not possible in CDMA");
    804             return false;
    805         }
    806     }
    807 
    808     @Override
    809     public void explicitCallTransfer() {
    810         if (isPhoneTypeGsm()) {
    811             mCT.explicitCallTransfer();
    812         } else {
    813             loge("explicitCallTransfer: not possible in CDMA");
    814         }
    815     }
    816 
    817     @Override
    818     public GsmCdmaCall getForegroundCall() {
    819         return mCT.mForegroundCall;
    820     }
    821 
    822     @Override
    823     public GsmCdmaCall getBackgroundCall() {
    824         return mCT.mBackgroundCall;
    825     }
    826 
    827     @Override
    828     public Call getRingingCall() {
    829         Phone imsPhone = mImsPhone;
    830         // It returns the ringing call of ImsPhone if the ringing call of GSMPhone isn't ringing.
    831         // In CallManager.registerPhone(), it always registers ringing call of ImsPhone, because
    832         // the ringing call of GSMPhone isn't ringing. Consequently, it can't answer GSM call
    833         // successfully by invoking TelephonyManager.answerRingingCall() since the implementation
    834         // in PhoneInterfaceManager.answerRingingCallInternal() could not get the correct ringing
    835         // call from CallManager. So we check the ringing call state of imsPhone first as
    836         // accpetCall() does.
    837         if ( imsPhone != null && imsPhone.getRingingCall().isRinging()) {
    838             return imsPhone.getRingingCall();
    839         }
    840         return mCT.mRingingCall;
    841     }
    842 
    843     private boolean handleCallDeflectionIncallSupplementaryService(
    844             String dialString) {
    845         if (dialString.length() > 1) {
    846             return false;
    847         }
    848 
    849         if (getRingingCall().getState() != GsmCdmaCall.State.IDLE) {
    850             if (DBG) logd("MmiCode 0: rejectCall");
    851             try {
    852                 mCT.rejectCall();
    853             } catch (CallStateException e) {
    854                 if (DBG) Rlog.d(LOG_TAG,
    855                         "reject failed", e);
    856                 notifySuppServiceFailed(Phone.SuppService.REJECT);
    857             }
    858         } else if (getBackgroundCall().getState() != GsmCdmaCall.State.IDLE) {
    859             if (DBG) logd("MmiCode 0: hangupWaitingOrBackground");
    860             mCT.hangupWaitingOrBackground();
    861         }
    862 
    863         return true;
    864     }
    865 
    866     //GSM
    867     private boolean handleCallWaitingIncallSupplementaryService(String dialString) {
    868         int len = dialString.length();
    869 
    870         if (len > 2) {
    871             return false;
    872         }
    873 
    874         GsmCdmaCall call = getForegroundCall();
    875 
    876         try {
    877             if (len > 1) {
    878                 char ch = dialString.charAt(1);
    879                 int callIndex = ch - '0';
    880 
    881                 if (callIndex >= 1 && callIndex <= GsmCdmaCallTracker.MAX_CONNECTIONS_GSM) {
    882                     if (DBG) logd("MmiCode 1: hangupConnectionByIndex " + callIndex);
    883                     mCT.hangupConnectionByIndex(call, callIndex);
    884                 }
    885             } else {
    886                 if (call.getState() != GsmCdmaCall.State.IDLE) {
    887                     if (DBG) logd("MmiCode 1: hangup foreground");
    888                     //mCT.hangupForegroundResumeBackground();
    889                     mCT.hangup(call);
    890                 } else {
    891                     if (DBG) logd("MmiCode 1: switchWaitingOrHoldingAndActive");
    892                     mCT.switchWaitingOrHoldingAndActive();
    893                 }
    894             }
    895         } catch (CallStateException e) {
    896             if (DBG) Rlog.d(LOG_TAG,
    897                     "hangup failed", e);
    898             notifySuppServiceFailed(Phone.SuppService.HANGUP);
    899         }
    900 
    901         return true;
    902     }
    903 
    904     private boolean handleCallHoldIncallSupplementaryService(String dialString) {
    905         int len = dialString.length();
    906 
    907         if (len > 2) {
    908             return false;
    909         }
    910 
    911         GsmCdmaCall call = getForegroundCall();
    912 
    913         if (len > 1) {
    914             try {
    915                 char ch = dialString.charAt(1);
    916                 int callIndex = ch - '0';
    917                 GsmCdmaConnection conn = mCT.getConnectionByIndex(call, callIndex);
    918 
    919                 // GsmCdma index starts at 1, up to 5 connections in a call,
    920                 if (conn != null && callIndex >= 1 && callIndex <= GsmCdmaCallTracker.MAX_CONNECTIONS_GSM) {
    921                     if (DBG) logd("MmiCode 2: separate call " + callIndex);
    922                     mCT.separate(conn);
    923                 } else {
    924                     if (DBG) logd("separate: invalid call index " + callIndex);
    925                     notifySuppServiceFailed(Phone.SuppService.SEPARATE);
    926                 }
    927             } catch (CallStateException e) {
    928                 if (DBG) Rlog.d(LOG_TAG, "separate failed", e);
    929                 notifySuppServiceFailed(Phone.SuppService.SEPARATE);
    930             }
    931         } else {
    932             try {
    933                 if (getRingingCall().getState() != GsmCdmaCall.State.IDLE) {
    934                     if (DBG) logd("MmiCode 2: accept ringing call");
    935                     mCT.acceptCall();
    936                 } else {
    937                     if (DBG) logd("MmiCode 2: switchWaitingOrHoldingAndActive");
    938                     mCT.switchWaitingOrHoldingAndActive();
    939                 }
    940             } catch (CallStateException e) {
    941                 if (DBG) Rlog.d(LOG_TAG, "switch failed", e);
    942                 notifySuppServiceFailed(Phone.SuppService.SWITCH);
    943             }
    944         }
    945 
    946         return true;
    947     }
    948 
    949     private boolean handleMultipartyIncallSupplementaryService(String dialString) {
    950         if (dialString.length() > 1) {
    951             return false;
    952         }
    953 
    954         if (DBG) logd("MmiCode 3: merge calls");
    955         conference();
    956         return true;
    957     }
    958 
    959     private boolean handleEctIncallSupplementaryService(String dialString) {
    960 
    961         int len = dialString.length();
    962 
    963         if (len != 1) {
    964             return false;
    965         }
    966 
    967         if (DBG) logd("MmiCode 4: explicit call transfer");
    968         explicitCallTransfer();
    969         return true;
    970     }
    971 
    972     private boolean handleCcbsIncallSupplementaryService(String dialString) {
    973         if (dialString.length() > 1) {
    974             return false;
    975         }
    976 
    977         Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!");
    978         // Treat it as an "unknown" service.
    979         notifySuppServiceFailed(Phone.SuppService.UNKNOWN);
    980         return true;
    981     }
    982 
    983     @Override
    984     public boolean handleInCallMmiCommands(String dialString) throws CallStateException {
    985         if (!isPhoneTypeGsm()) {
    986             loge("method handleInCallMmiCommands is NOT supported in CDMA!");
    987             return false;
    988         }
    989 
    990         Phone imsPhone = mImsPhone;
    991         if (imsPhone != null
    992                 && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
    993             return imsPhone.handleInCallMmiCommands(dialString);
    994         }
    995 
    996         if (!isInCall()) {
    997             return false;
    998         }
    999 
   1000         if (TextUtils.isEmpty(dialString)) {
   1001             return false;
   1002         }
   1003 
   1004         boolean result = false;
   1005         char ch = dialString.charAt(0);
   1006         switch (ch) {
   1007             case '0':
   1008                 result = handleCallDeflectionIncallSupplementaryService(dialString);
   1009                 break;
   1010             case '1':
   1011                 result = handleCallWaitingIncallSupplementaryService(dialString);
   1012                 break;
   1013             case '2':
   1014                 result = handleCallHoldIncallSupplementaryService(dialString);
   1015                 break;
   1016             case '3':
   1017                 result = handleMultipartyIncallSupplementaryService(dialString);
   1018                 break;
   1019             case '4':
   1020                 result = handleEctIncallSupplementaryService(dialString);
   1021                 break;
   1022             case '5':
   1023                 result = handleCcbsIncallSupplementaryService(dialString);
   1024                 break;
   1025             default:
   1026                 break;
   1027         }
   1028 
   1029         return result;
   1030     }
   1031 
   1032     public boolean isInCall() {
   1033         GsmCdmaCall.State foregroundCallState = getForegroundCall().getState();
   1034         GsmCdmaCall.State backgroundCallState = getBackgroundCall().getState();
   1035         GsmCdmaCall.State ringingCallState = getRingingCall().getState();
   1036 
   1037        return (foregroundCallState.isAlive() ||
   1038                 backgroundCallState.isAlive() ||
   1039                 ringingCallState.isAlive());
   1040     }
   1041 
   1042     @Override
   1043     public Connection dial(String dialString, @NonNull DialArgs dialArgs)
   1044             throws CallStateException {
   1045         if (!isPhoneTypeGsm() && dialArgs.uusInfo != null) {
   1046             throw new CallStateException("Sending UUS information NOT supported in CDMA!");
   1047         }
   1048 
   1049         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
   1050         Phone imsPhone = mImsPhone;
   1051 
   1052         CarrierConfigManager configManager =
   1053                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
   1054         boolean alwaysTryImsForEmergencyCarrierConfig = configManager.getConfigForSubId(getSubId())
   1055                 .getBoolean(CarrierConfigManager.KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL);
   1056 
   1057         boolean useImsForCall = isImsUseEnabled()
   1058                  && imsPhone != null
   1059                  && (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled() ||
   1060                  (imsPhone.isVideoEnabled() && VideoProfile.isVideo(dialArgs.videoState)))
   1061                  && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
   1062 
   1063         boolean useImsForEmergency = imsPhone != null
   1064                 && isEmergency
   1065                 && alwaysTryImsForEmergencyCarrierConfig
   1066                 && ImsManager.getInstance(mContext, mPhoneId).isNonTtyOrTtyOnVolteEnabled()
   1067                 && imsPhone.isImsAvailable();
   1068 
   1069         String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.
   1070                 stripSeparators(dialString));
   1071         boolean isUt = (dialPart.startsWith("*") || dialPart.startsWith("#"))
   1072                 && dialPart.endsWith("#");
   1073 
   1074         boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled();
   1075 
   1076         if (DBG) {
   1077             logd("useImsForCall=" + useImsForCall
   1078                     + ", useImsForEmergency=" + useImsForEmergency
   1079                     + ", useImsForUt=" + useImsForUt
   1080                     + ", isUt=" + isUt
   1081                     + ", imsPhone=" + imsPhone
   1082                     + ", imsPhone.isVolteEnabled()="
   1083                     + ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A")
   1084                     + ", imsPhone.isVowifiEnabled()="
   1085                     + ((imsPhone != null) ? imsPhone.isWifiCallingEnabled() : "N/A")
   1086                     + ", imsPhone.isVideoEnabled()="
   1087                     + ((imsPhone != null) ? imsPhone.isVideoEnabled() : "N/A")
   1088                     + ", imsPhone.getServiceState().getState()="
   1089                     + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A"));
   1090         }
   1091 
   1092         Phone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mPhoneId, mContext);
   1093 
   1094         if ((useImsForCall && !isUt) || (isUt && useImsForUt) || useImsForEmergency) {
   1095             try {
   1096                 if (DBG) logd("Trying IMS PS call");
   1097                 return imsPhone.dial(dialString, dialArgs);
   1098             } catch (CallStateException e) {
   1099                 if (DBG) logd("IMS PS call exception " + e +
   1100                         "useImsForCall =" + useImsForCall + ", imsPhone =" + imsPhone);
   1101                 // Do not throw a CallStateException and instead fall back to Circuit switch
   1102                 // for emergency calls and MMI codes.
   1103                 if (Phone.CS_FALLBACK.equals(e.getMessage()) || isEmergency) {
   1104                     logi("IMS call failed with Exception: " + e.getMessage() + ". Falling back "
   1105                             + "to CS.");
   1106                 } else {
   1107                     CallStateException ce = new CallStateException(e.getMessage());
   1108                     ce.setStackTrace(e.getStackTrace());
   1109                     throw ce;
   1110                 }
   1111             }
   1112         }
   1113 
   1114         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE
   1115                 && mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) {
   1116             throw new CallStateException("cannot dial in current state");
   1117         }
   1118         // Check non-emergency voice CS call - shouldn't dial when POWER_OFF
   1119         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_POWER_OFF /* CS POWER_OFF */
   1120                 && !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
   1121                 && !isEmergency /* non-emergency call */) {
   1122             throw new CallStateException(
   1123                 CallStateException.ERROR_POWER_OFF,
   1124                 "cannot dial voice call in airplane mode");
   1125         }
   1126         // Check for service before placing non emergency CS voice call.
   1127         // Allow dial only if either CS is camped on any RAT (or) PS is in LTE service.
   1128         if (mSST != null
   1129                 && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE /* CS out of service */
   1130                 && !(mSST.mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
   1131                     && ServiceState.isLte(mSST.mSS.getRilDataRadioTechnology())) /* PS not in LTE */
   1132                 && !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
   1133                 && !isEmergency /* non-emergency call */) {
   1134             throw new CallStateException(
   1135                 CallStateException.ERROR_OUT_OF_SERVICE,
   1136                 "cannot dial voice call in out of service");
   1137         }
   1138         if (DBG) logd("Trying (non-IMS) CS call");
   1139 
   1140         if (isPhoneTypeGsm()) {
   1141             return dialInternal(dialString, new DialArgs.Builder<>()
   1142                     .setIntentExtras(dialArgs.intentExtras)
   1143                     .build());
   1144         } else {
   1145             return dialInternal(dialString, dialArgs);
   1146         }
   1147     }
   1148 
   1149     /**
   1150      * @return {@code true} if the user should be informed of an attempt to dial an international
   1151      * number while on WFC only, {@code false} otherwise.
   1152      */
   1153     public boolean isNotificationOfWfcCallRequired(String dialString) {
   1154         CarrierConfigManager configManager =
   1155                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
   1156         PersistableBundle config = configManager.getConfigForSubId(getSubId());
   1157 
   1158         // Determine if carrier config indicates that international calls over WFC should trigger a
   1159         // notification to the user. This is controlled by carrier configuration and is off by
   1160         // default.
   1161         boolean shouldNotifyInternationalCallOnWfc = config != null
   1162                 && config.getBoolean(
   1163                         CarrierConfigManager.KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL);
   1164 
   1165         if (!shouldNotifyInternationalCallOnWfc) {
   1166             return false;
   1167         }
   1168 
   1169         Phone imsPhone = mImsPhone;
   1170         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
   1171         boolean shouldConfirmCall =
   1172                         // Using IMS
   1173                         isImsUseEnabled()
   1174                         && imsPhone != null
   1175                         // VoLTE not available
   1176                         && !imsPhone.isVolteEnabled()
   1177                         // WFC is available
   1178                         && imsPhone.isWifiCallingEnabled()
   1179                         && !isEmergency
   1180                         // Dialing international number
   1181                         && PhoneNumberUtils.isInternationalNumber(dialString, getCountryIso());
   1182         return shouldConfirmCall;
   1183     }
   1184 
   1185     @Override
   1186     protected Connection dialInternal(String dialString, DialArgs dialArgs)
   1187             throws CallStateException {
   1188         return dialInternal(dialString, dialArgs, null);
   1189     }
   1190 
   1191     protected Connection dialInternal(String dialString, DialArgs dialArgs,
   1192             ResultReceiver wrappedCallback)
   1193             throws CallStateException {
   1194 
   1195         // Need to make sure dialString gets parsed properly
   1196         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
   1197 
   1198         if (isPhoneTypeGsm()) {
   1199             // handle in-call MMI first if applicable
   1200             if (handleInCallMmiCommands(newDialString)) {
   1201                 return null;
   1202             }
   1203 
   1204             // Only look at the Network portion for mmi
   1205             String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
   1206             GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
   1207                     mUiccApplication.get(), wrappedCallback);
   1208             if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");
   1209 
   1210             if (mmi == null) {
   1211                 return mCT.dial(newDialString, dialArgs.uusInfo, dialArgs.intentExtras);
   1212             } else if (mmi.isTemporaryModeCLIR()) {
   1213                 return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), dialArgs.uusInfo,
   1214                         dialArgs.intentExtras);
   1215             } else {
   1216                 mPendingMMIs.add(mmi);
   1217                 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
   1218                 mmi.processCode();
   1219                 return null;
   1220             }
   1221         } else {
   1222             return mCT.dial(newDialString);
   1223         }
   1224     }
   1225 
   1226    @Override
   1227     public boolean handlePinMmi(String dialString) {
   1228         MmiCode mmi;
   1229         if (isPhoneTypeGsm()) {
   1230             mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
   1231         } else {
   1232             mmi = CdmaMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
   1233         }
   1234 
   1235         if (mmi != null && mmi.isPinPukCommand()) {
   1236             mPendingMMIs.add(mmi);
   1237             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
   1238             try {
   1239                 mmi.processCode();
   1240             } catch (CallStateException e) {
   1241                 //do nothing
   1242             }
   1243             return true;
   1244         }
   1245 
   1246         loge("Mmi is null or unrecognized!");
   1247         return false;
   1248     }
   1249 
   1250     private void sendUssdResponse(String ussdRequest, CharSequence message, int returnCode,
   1251                                    ResultReceiver wrappedCallback) {
   1252         UssdResponse response = new UssdResponse(ussdRequest, message);
   1253         Bundle returnData = new Bundle();
   1254         returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
   1255         wrappedCallback.send(returnCode, returnData);
   1256     }
   1257 
   1258     @Override
   1259     public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
   1260         if (!isPhoneTypeGsm() || mPendingMMIs.size() > 0) {
   1261             //todo: replace the generic failure with specific error code.
   1262             sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
   1263                     wrappedCallback );
   1264             return true;
   1265         }
   1266 
   1267         // Try over IMS if possible.
   1268         Phone imsPhone = mImsPhone;
   1269         if ((imsPhone != null)
   1270                 && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1271                 || imsPhone.isUtEnabled())) {
   1272             try {
   1273                 logd("handleUssdRequest: attempting over IMS");
   1274                 return imsPhone.handleUssdRequest(ussdRequest, wrappedCallback);
   1275             } catch (CallStateException cse) {
   1276                 if (!CS_FALLBACK.equals(cse.getMessage())) {
   1277                     return false;
   1278                 }
   1279                 // At this point we've tried over IMS but have been informed we need to handover
   1280                 // back to GSM.
   1281                 logd("handleUssdRequest: fallback to CS required");
   1282             }
   1283         }
   1284 
   1285         // Try USSD over GSM.
   1286         try {
   1287             dialInternal(ussdRequest, new DialArgs.Builder<>().build(), wrappedCallback);
   1288         } catch (Exception e) {
   1289             logd("handleUssdRequest: exception" + e);
   1290             return false;
   1291         }
   1292         return true;
   1293     }
   1294 
   1295     @Override
   1296     public void sendUssdResponse(String ussdMessge) {
   1297         if (isPhoneTypeGsm()) {
   1298             GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get());
   1299             mPendingMMIs.add(mmi);
   1300             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
   1301             mmi.sendUssd(ussdMessge);
   1302         } else {
   1303             loge("sendUssdResponse: not possible in CDMA");
   1304         }
   1305     }
   1306 
   1307     @Override
   1308     public void sendDtmf(char c) {
   1309         if (!PhoneNumberUtils.is12Key(c)) {
   1310             loge("sendDtmf called with invalid character '" + c + "'");
   1311         } else {
   1312             if (mCT.mState ==  PhoneConstants.State.OFFHOOK) {
   1313                 mCi.sendDtmf(c, null);
   1314             }
   1315         }
   1316     }
   1317 
   1318     @Override
   1319     public void startDtmf(char c) {
   1320         if (!PhoneNumberUtils.is12Key(c)) {
   1321             loge("startDtmf called with invalid character '" + c + "'");
   1322         } else {
   1323             mCi.startDtmf(c, null);
   1324         }
   1325     }
   1326 
   1327     @Override
   1328     public void stopDtmf() {
   1329         mCi.stopDtmf(null);
   1330     }
   1331 
   1332     @Override
   1333     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
   1334         if (isPhoneTypeGsm()) {
   1335             loge("[GsmCdmaPhone] sendBurstDtmf() is a CDMA method");
   1336         } else {
   1337             boolean check = true;
   1338             for (int itr = 0;itr < dtmfString.length(); itr++) {
   1339                 if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
   1340                     Rlog.e(LOG_TAG,
   1341                             "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
   1342                     check = false;
   1343                     break;
   1344                 }
   1345             }
   1346             if (mCT.mState == PhoneConstants.State.OFFHOOK && check) {
   1347                 mCi.sendBurstDtmf(dtmfString, on, off, onComplete);
   1348             }
   1349         }
   1350     }
   1351 
   1352     @Override
   1353     public void setRadioPower(boolean power) {
   1354         mSST.setRadioPower(power);
   1355     }
   1356 
   1357     private void storeVoiceMailNumber(String number) {
   1358         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   1359         SharedPreferences.Editor editor = sp.edit();
   1360         if (isPhoneTypeGsm()) {
   1361             editor.putString(VM_NUMBER + getPhoneId(), number);
   1362             editor.apply();
   1363             setVmSimImsi(getSubscriberId());
   1364         } else {
   1365             editor.putString(VM_NUMBER_CDMA + getPhoneId(), number);
   1366             editor.apply();
   1367         }
   1368     }
   1369 
   1370     @Override
   1371     public String getVoiceMailNumber() {
   1372         String number = null;
   1373         if (isPhoneTypeGsm()) {
   1374             // Read from the SIM. If its null, try reading from the shared preference area.
   1375             IccRecords r = mIccRecords.get();
   1376             number = (r != null) ? r.getVoiceMailNumber() : "";
   1377             if (TextUtils.isEmpty(number)) {
   1378                 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   1379                 number = sp.getString(VM_NUMBER + getPhoneId(), null);
   1380             }
   1381         } else {
   1382             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   1383             number = sp.getString(VM_NUMBER_CDMA + getPhoneId(), null);
   1384         }
   1385 
   1386         if (TextUtils.isEmpty(number)) {
   1387             CarrierConfigManager configManager = (CarrierConfigManager)
   1388                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
   1389             PersistableBundle b = configManager.getConfig();
   1390             if (b != null) {
   1391                 String defaultVmNumber =
   1392                         b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING);
   1393                 String defaultVmNumberRoaming =
   1394                         b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_ROAMING_STRING);
   1395                 if (!TextUtils.isEmpty(defaultVmNumberRoaming) && mSST.mSS.getRoaming()) {
   1396                     number = defaultVmNumberRoaming;
   1397                 } else {
   1398                     number = defaultVmNumber;
   1399                 }
   1400             }
   1401         }
   1402 
   1403         if (!isPhoneTypeGsm() && TextUtils.isEmpty(number)) {
   1404             // Read platform settings for dynamic voicemail number
   1405             CarrierConfigManager configManager = (CarrierConfigManager)
   1406                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
   1407             PersistableBundle b = configManager.getConfig();
   1408             if (b != null && b.getBoolean(
   1409                     CarrierConfigManager.KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL)) {
   1410                 number = getLine1Number();
   1411             } else {
   1412                 number = "*86";
   1413             }
   1414         }
   1415 
   1416         return number;
   1417     }
   1418 
   1419     private String getVmSimImsi() {
   1420         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   1421         return sp.getString(VM_SIM_IMSI + getPhoneId(), null);
   1422     }
   1423 
   1424     private void setVmSimImsi(String imsi) {
   1425         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   1426         SharedPreferences.Editor editor = sp.edit();
   1427         editor.putString(VM_SIM_IMSI + getPhoneId(), imsi);
   1428         editor.apply();
   1429     }
   1430 
   1431     @Override
   1432     public String getVoiceMailAlphaTag() {
   1433         String ret = "";
   1434 
   1435         if (isPhoneTypeGsm()) {
   1436             IccRecords r = mIccRecords.get();
   1437 
   1438             ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
   1439         }
   1440 
   1441         if (ret == null || ret.length() == 0) {
   1442             return mContext.getText(
   1443                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
   1444         }
   1445 
   1446         return ret;
   1447     }
   1448 
   1449     @Override
   1450     public String getDeviceId() {
   1451         if (isPhoneTypeGsm()) {
   1452             return mImei;
   1453         } else {
   1454             CarrierConfigManager configManager = (CarrierConfigManager)
   1455                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
   1456             boolean force_imei = configManager.getConfigForSubId(getSubId())
   1457                     .getBoolean(CarrierConfigManager.KEY_FORCE_IMEI_BOOL);
   1458             if (force_imei) return mImei;
   1459 
   1460             String id = getMeid();
   1461             if ((id == null) || id.matches("^0*$")) {
   1462                 loge("getDeviceId(): MEID is not initialized use ESN");
   1463                 id = getEsn();
   1464             }
   1465             return id;
   1466         }
   1467     }
   1468 
   1469     @Override
   1470     public String getDeviceSvn() {
   1471         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
   1472             return mImeiSv;
   1473         } else {
   1474             loge("getDeviceSvn(): return 0");
   1475             return "0";
   1476         }
   1477     }
   1478 
   1479     @Override
   1480     public IsimRecords getIsimRecords() {
   1481         return mIsimUiccRecords;
   1482     }
   1483 
   1484     @Override
   1485     public String getImei() {
   1486         return mImei;
   1487     }
   1488 
   1489     @Override
   1490     public String getEsn() {
   1491         if (isPhoneTypeGsm()) {
   1492             loge("[GsmCdmaPhone] getEsn() is a CDMA method");
   1493             return "0";
   1494         } else {
   1495             return mEsn;
   1496         }
   1497     }
   1498 
   1499     @Override
   1500     public String getMeid() {
   1501         return mMeid;
   1502     }
   1503 
   1504     @Override
   1505     public String getNai() {
   1506         IccRecords r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP2);
   1507         if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
   1508             Rlog.v(LOG_TAG, "IccRecords is " + r);
   1509         }
   1510         return (r != null) ? r.getNAI() : null;
   1511     }
   1512 
   1513     @Override
   1514     @Nullable
   1515     public String getSubscriberId() {
   1516         String subscriberId = null;
   1517         if (isPhoneTypeCdma()) {
   1518             subscriberId = mSST.getImsi();
   1519         } else {
   1520             // Both Gsm and CdmaLte get the IMSI from Usim.
   1521             IccRecords iccRecords = mUiccController.getIccRecords(
   1522                     mPhoneId, UiccController.APP_FAM_3GPP);
   1523             if (iccRecords != null) {
   1524                 subscriberId = iccRecords.getIMSI();
   1525             }
   1526         }
   1527         return subscriberId;
   1528     }
   1529 
   1530     @Override
   1531     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
   1532         return CarrierInfoManager.getCarrierInfoForImsiEncryption(keyType, mContext);
   1533     }
   1534 
   1535     @Override
   1536     public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) {
   1537         CarrierInfoManager.setCarrierInfoForImsiEncryption(imsiEncryptionInfo, mContext, mPhoneId);
   1538     }
   1539 
   1540     @Override
   1541     public int getCarrierId() {
   1542         return mCarrerIdentifier.getCarrierId();
   1543     }
   1544 
   1545     @Override
   1546     public String getCarrierName() {
   1547         return mCarrerIdentifier.getCarrierName();
   1548     }
   1549 
   1550     @Override
   1551     public int getCarrierIdListVersion() {
   1552         return mCarrerIdentifier.getCarrierListVersion();
   1553     }
   1554 
   1555     @Override
   1556     public void resetCarrierKeysForImsiEncryption() {
   1557         mCIM.resetCarrierKeysForImsiEncryption(mContext, mPhoneId);
   1558     }
   1559 
   1560     @Override
   1561     public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
   1562             String gid2, String pnn, String spn) {
   1563         IccRecords r = null;
   1564         if (isPhoneTypeGsm()) {
   1565             r = mIccRecords.get();
   1566         } else if (isPhoneTypeCdmaLte()) {
   1567             r = mSimRecords;
   1568         } else {
   1569             loge("setCarrierTestOverride fails in CDMA only");
   1570         }
   1571         if (r != null) {
   1572             r.setCarrierTestOverride(mccmnc, imsi, iccid, gid1, gid2, pnn, spn);
   1573         }
   1574     }
   1575 
   1576     @Override
   1577     public String getGroupIdLevel1() {
   1578         if (isPhoneTypeGsm()) {
   1579             IccRecords r = mIccRecords.get();
   1580             return (r != null) ? r.getGid1() : null;
   1581         } else if (isPhoneTypeCdma()) {
   1582             loge("GID1 is not available in CDMA");
   1583             return null;
   1584         } else { //isPhoneTypeCdmaLte()
   1585             return (mSimRecords != null) ? mSimRecords.getGid1() : "";
   1586         }
   1587     }
   1588 
   1589     @Override
   1590     public String getGroupIdLevel2() {
   1591         if (isPhoneTypeGsm()) {
   1592             IccRecords r = mIccRecords.get();
   1593             return (r != null) ? r.getGid2() : null;
   1594         } else if (isPhoneTypeCdma()) {
   1595             loge("GID2 is not available in CDMA");
   1596             return null;
   1597         } else { //isPhoneTypeCdmaLte()
   1598             return (mSimRecords != null) ? mSimRecords.getGid2() : "";
   1599         }
   1600     }
   1601 
   1602     @Override
   1603     public String getLine1Number() {
   1604         if (isPhoneTypeGsm()) {
   1605             IccRecords r = mIccRecords.get();
   1606             return (r != null) ? r.getMsisdnNumber() : null;
   1607         } else {
   1608             return mSST.getMdnNumber();
   1609         }
   1610     }
   1611 
   1612     @Override
   1613     public String getPlmn() {
   1614         if (isPhoneTypeGsm()) {
   1615             IccRecords r = mIccRecords.get();
   1616             return (r != null) ? r.getPnnHomeName() : null;
   1617         } else if (isPhoneTypeCdma()) {
   1618             loge("Plmn is not available in CDMA");
   1619             return null;
   1620         } else { //isPhoneTypeCdmaLte()
   1621             return (mSimRecords != null) ? mSimRecords.getPnnHomeName() : null;
   1622         }
   1623     }
   1624 
   1625     @Override
   1626     public String getCdmaPrlVersion() {
   1627         return mSST.getPrlVersion();
   1628     }
   1629 
   1630     @Override
   1631     public String getCdmaMin() {
   1632         return mSST.getCdmaMin();
   1633     }
   1634 
   1635     @Override
   1636     public boolean isMinInfoReady() {
   1637         return mSST.isMinInfoReady();
   1638     }
   1639 
   1640     @Override
   1641     public String getMsisdn() {
   1642         if (isPhoneTypeGsm()) {
   1643             IccRecords r = mIccRecords.get();
   1644             return (r != null) ? r.getMsisdnNumber() : null;
   1645         } else if (isPhoneTypeCdmaLte()) {
   1646             return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null;
   1647         } else {
   1648             loge("getMsisdn: not expected on CDMA");
   1649             return null;
   1650         }
   1651     }
   1652 
   1653     @Override
   1654     public String getLine1AlphaTag() {
   1655         if (isPhoneTypeGsm()) {
   1656             IccRecords r = mIccRecords.get();
   1657             return (r != null) ? r.getMsisdnAlphaTag() : null;
   1658         } else {
   1659             loge("getLine1AlphaTag: not possible in CDMA");
   1660             return null;
   1661         }
   1662     }
   1663 
   1664     @Override
   1665     public boolean setLine1Number(String alphaTag, String number, Message onComplete) {
   1666         if (isPhoneTypeGsm()) {
   1667             IccRecords r = mIccRecords.get();
   1668             if (r != null) {
   1669                 r.setMsisdnNumber(alphaTag, number, onComplete);
   1670                 return true;
   1671             } else {
   1672                 return false;
   1673             }
   1674         } else {
   1675             loge("setLine1Number: not possible in CDMA");
   1676             return false;
   1677         }
   1678     }
   1679 
   1680     @Override
   1681     public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) {
   1682         Message resp;
   1683         mVmNumber = voiceMailNumber;
   1684         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
   1685         IccRecords r = mIccRecords.get();
   1686         if (r != null) {
   1687             r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
   1688         }
   1689     }
   1690 
   1691     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
   1692         switch (commandInterfaceCFReason) {
   1693             case CF_REASON_UNCONDITIONAL:
   1694             case CF_REASON_BUSY:
   1695             case CF_REASON_NO_REPLY:
   1696             case CF_REASON_NOT_REACHABLE:
   1697             case CF_REASON_ALL:
   1698             case CF_REASON_ALL_CONDITIONAL:
   1699                 return true;
   1700             default:
   1701                 return false;
   1702         }
   1703     }
   1704 
   1705     @Override
   1706     public String getSystemProperty(String property, String defValue) {
   1707         if (getUnitTestMode()) {
   1708             return null;
   1709         }
   1710         return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue);
   1711     }
   1712 
   1713     private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
   1714         switch (commandInterfaceCFAction) {
   1715             case CF_ACTION_DISABLE:
   1716             case CF_ACTION_ENABLE:
   1717             case CF_ACTION_REGISTRATION:
   1718             case CF_ACTION_ERASURE:
   1719                 return true;
   1720             default:
   1721                 return false;
   1722         }
   1723     }
   1724 
   1725     private boolean isCfEnable(int action) {
   1726         return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
   1727     }
   1728 
   1729     @Override
   1730     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
   1731         if (isPhoneTypeGsm()) {
   1732             Phone imsPhone = mImsPhone;
   1733             if ((imsPhone != null)
   1734                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1735                     || imsPhone.isUtEnabled())) {
   1736                 imsPhone.getCallForwardingOption(commandInterfaceCFReason, onComplete);
   1737                 return;
   1738             }
   1739 
   1740             if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
   1741                 if (DBG) logd("requesting call forwarding query.");
   1742                 Message resp;
   1743                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
   1744                     resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
   1745                 } else {
   1746                     resp = onComplete;
   1747                 }
   1748                 mCi.queryCallForwardStatus(commandInterfaceCFReason,
   1749                         CommandsInterface.SERVICE_CLASS_VOICE, null, resp);
   1750             }
   1751         } else {
   1752             loge("getCallForwardingOption: not possible in CDMA");
   1753         }
   1754     }
   1755 
   1756     @Override
   1757     public void setCallForwardingOption(int commandInterfaceCFAction,
   1758             int commandInterfaceCFReason,
   1759             String dialingNumber,
   1760             int timerSeconds,
   1761             Message onComplete) {
   1762         if (isPhoneTypeGsm()) {
   1763             Phone imsPhone = mImsPhone;
   1764             if ((imsPhone != null)
   1765                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1766                     || imsPhone.isUtEnabled())) {
   1767                 imsPhone.setCallForwardingOption(commandInterfaceCFAction,
   1768                         commandInterfaceCFReason, dialingNumber, timerSeconds, onComplete);
   1769                 return;
   1770             }
   1771 
   1772             if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
   1773                     (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
   1774 
   1775                 Message resp;
   1776                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
   1777                     Cfu cfu = new Cfu(dialingNumber, onComplete);
   1778                     resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
   1779                             isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu);
   1780                 } else {
   1781                     resp = onComplete;
   1782                 }
   1783                 mCi.setCallForward(commandInterfaceCFAction,
   1784                         commandInterfaceCFReason,
   1785                         CommandsInterface.SERVICE_CLASS_VOICE,
   1786                         dialingNumber,
   1787                         timerSeconds,
   1788                         resp);
   1789             }
   1790         } else {
   1791             loge("setCallForwardingOption: not possible in CDMA");
   1792         }
   1793     }
   1794 
   1795     @Override
   1796     public void getCallBarring(String facility, String password, Message onComplete,
   1797             int serviceClass) {
   1798         if (isPhoneTypeGsm()) {
   1799             Phone imsPhone = mImsPhone;
   1800             if ((imsPhone != null)
   1801                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1802                     || imsPhone.isUtEnabled())) {
   1803                 imsPhone.getCallBarring(facility, password, onComplete, serviceClass);
   1804                 return;
   1805             }
   1806             mCi.queryFacilityLock(facility, password, serviceClass, onComplete);
   1807         } else {
   1808             loge("getCallBarringOption: not possible in CDMA");
   1809         }
   1810     }
   1811 
   1812     @Override
   1813     public void setCallBarring(String facility, boolean lockState, String password,
   1814             Message onComplete, int serviceClass) {
   1815         if (isPhoneTypeGsm()) {
   1816             Phone imsPhone = mImsPhone;
   1817             if ((imsPhone != null)
   1818                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1819                     || imsPhone.isUtEnabled())) {
   1820                 imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass);
   1821                 return;
   1822             }
   1823             mCi.setFacilityLock(facility, lockState, password, serviceClass, onComplete);
   1824         } else {
   1825             loge("setCallBarringOption: not possible in CDMA");
   1826         }
   1827     }
   1828 
   1829     /**
   1830      * Changes access code used for call barring
   1831      *
   1832      * @param facility is one of CB_FACILTY_*
   1833      * @param oldPwd is old password
   1834      * @param newPwd is new password
   1835      * @param onComplete is callback message when the action is completed.
   1836      */
   1837     public void changeCallBarringPassword(String facility, String oldPwd, String newPwd,
   1838             Message onComplete) {
   1839         if (isPhoneTypeGsm()) {
   1840             mCi.changeBarringPassword(facility, oldPwd, newPwd, onComplete);
   1841         } else {
   1842             loge("changeCallBarringPassword: not possible in CDMA");
   1843         }
   1844     }
   1845 
   1846     @Override
   1847     public void getOutgoingCallerIdDisplay(Message onComplete) {
   1848         if (isPhoneTypeGsm()) {
   1849             Phone imsPhone = mImsPhone;
   1850             if ((imsPhone != null)
   1851                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1852                     || imsPhone.isUtEnabled())) {
   1853                 imsPhone.getOutgoingCallerIdDisplay(onComplete);
   1854                 return;
   1855             }
   1856             mCi.getCLIR(onComplete);
   1857         } else {
   1858             loge("getOutgoingCallerIdDisplay: not possible in CDMA");
   1859         }
   1860     }
   1861 
   1862     @Override
   1863     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
   1864         if (isPhoneTypeGsm()) {
   1865             Phone imsPhone = mImsPhone;
   1866             if ((imsPhone != null)
   1867                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1868                     || imsPhone.isUtEnabled())) {
   1869                 imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete);
   1870                 return;
   1871             }
   1872             // Packing CLIR value in the message. This will be required for
   1873             // SharedPreference caching, if the message comes back as part of
   1874             // a success response.
   1875             mCi.setCLIR(commandInterfaceCLIRMode,
   1876                     obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
   1877         } else {
   1878             loge("setOutgoingCallerIdDisplay: not possible in CDMA");
   1879         }
   1880     }
   1881 
   1882     @Override
   1883     public void getCallWaiting(Message onComplete) {
   1884         if (isPhoneTypeGsm()) {
   1885             Phone imsPhone = mImsPhone;
   1886             if ((imsPhone != null)
   1887                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1888                     || imsPhone.isUtEnabled())) {
   1889                 imsPhone.getCallWaiting(onComplete);
   1890                 return;
   1891             }
   1892 
   1893             //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
   1894             //class parameter in call waiting interrogation  to network
   1895             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
   1896         } else {
   1897             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
   1898         }
   1899     }
   1900 
   1901     @Override
   1902     public void setCallWaiting(boolean enable, Message onComplete) {
   1903         if (isPhoneTypeGsm()) {
   1904             Phone imsPhone = mImsPhone;
   1905             if ((imsPhone != null)
   1906                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
   1907                     || imsPhone.isUtEnabled())) {
   1908                 imsPhone.setCallWaiting(enable, onComplete);
   1909                 return;
   1910             }
   1911 
   1912             mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
   1913         } else {
   1914             loge("method setCallWaiting is NOT supported in CDMA!");
   1915         }
   1916     }
   1917 
   1918     @Override
   1919     public void getAvailableNetworks(Message response) {
   1920         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
   1921             mCi.getAvailableNetworks(response);
   1922         } else {
   1923             loge("getAvailableNetworks: not possible in CDMA");
   1924         }
   1925     }
   1926 
   1927     @Override
   1928     public void startNetworkScan(NetworkScanRequest nsr, Message response) {
   1929         mCi.startNetworkScan(nsr, response);
   1930     }
   1931 
   1932     @Override
   1933     public void stopNetworkScan(Message response) {
   1934         mCi.stopNetworkScan(response);
   1935     }
   1936 
   1937     @Override
   1938     public void getNeighboringCids(Message response, WorkSource workSource) {
   1939         if (isPhoneTypeGsm()) {
   1940             mCi.getNeighboringCids(response, workSource);
   1941         } else {
   1942             /*
   1943              * This is currently not implemented.  At least as of June
   1944              * 2009, there is no neighbor cell information available for
   1945              * CDMA because some party is resisting making this
   1946              * information readily available.  Consequently, calling this
   1947              * function can have no useful effect.  This situation may
   1948              * (and hopefully will) change in the future.
   1949              */
   1950             if (response != null) {
   1951                 CommandException ce = new CommandException(
   1952                         CommandException.Error.REQUEST_NOT_SUPPORTED);
   1953                 AsyncResult.forMessage(response).exception = ce;
   1954                 response.sendToTarget();
   1955             }
   1956         }
   1957     }
   1958 
   1959     @Override
   1960     public void setTTYMode(int ttyMode, Message onComplete) {
   1961         // Send out the TTY Mode change over RIL as well
   1962         super.setTTYMode(ttyMode, onComplete);
   1963         if (mImsPhone != null) {
   1964             mImsPhone.setTTYMode(ttyMode, onComplete);
   1965         }
   1966     }
   1967 
   1968     @Override
   1969     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
   1970        if (mImsPhone != null) {
   1971            mImsPhone.setUiTTYMode(uiTtyMode, onComplete);
   1972        }
   1973     }
   1974 
   1975     @Override
   1976     public void setMute(boolean muted) {
   1977         mCT.setMute(muted);
   1978     }
   1979 
   1980     @Override
   1981     public boolean getMute() {
   1982         return mCT.getMute();
   1983     }
   1984 
   1985     @Override
   1986     public void updateServiceLocation() {
   1987         mSST.enableSingleLocationUpdate();
   1988     }
   1989 
   1990     @Override
   1991     public void enableLocationUpdates() {
   1992         mSST.enableLocationUpdates();
   1993     }
   1994 
   1995     @Override
   1996     public void disableLocationUpdates() {
   1997         mSST.disableLocationUpdates();
   1998     }
   1999 
   2000     @Override
   2001     public boolean getDataRoamingEnabled() {
   2002         return mDcTracker.getDataRoamingEnabled();
   2003     }
   2004 
   2005     @Override
   2006     public void setDataRoamingEnabled(boolean enable) {
   2007         mDcTracker.setDataRoamingEnabledByUser(enable);
   2008     }
   2009 
   2010     @Override
   2011     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
   2012         mCi.registerForCdmaOtaProvision(h, what, obj);
   2013     }
   2014 
   2015     @Override
   2016     public void unregisterForCdmaOtaStatusChange(Handler h) {
   2017         mCi.unregisterForCdmaOtaProvision(h);
   2018     }
   2019 
   2020     @Override
   2021     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
   2022         mSST.registerForSubscriptionInfoReady(h, what, obj);
   2023     }
   2024 
   2025     @Override
   2026     public void unregisterForSubscriptionInfoReady(Handler h) {
   2027         mSST.unregisterForSubscriptionInfoReady(h);
   2028     }
   2029 
   2030     @Override
   2031     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
   2032         mEcmExitRespRegistrant = new Registrant(h, what, obj);
   2033     }
   2034 
   2035     @Override
   2036     public void unsetOnEcbModeExitResponse(Handler h) {
   2037         mEcmExitRespRegistrant.clear();
   2038     }
   2039 
   2040     @Override
   2041     public void registerForCallWaiting(Handler h, int what, Object obj) {
   2042         mCT.registerForCallWaiting(h, what, obj);
   2043     }
   2044 
   2045     @Override
   2046     public void unregisterForCallWaiting(Handler h) {
   2047         mCT.unregisterForCallWaiting(h);
   2048     }
   2049 
   2050     @Override
   2051     public boolean isUserDataEnabled() {
   2052         return mDcTracker.isUserDataEnabled();
   2053     }
   2054 
   2055     @Override
   2056     public boolean isDataEnabled() {
   2057         return mDcTracker.isDataEnabled();
   2058     }
   2059 
   2060     @Override
   2061     public void setUserDataEnabled(boolean enable) {
   2062         mDcTracker.setUserDataEnabled(enable);
   2063     }
   2064 
   2065     /**
   2066      * Removes the given MMI from the pending list and notifies
   2067      * registrants that it is complete.
   2068      * @param mmi MMI that is done
   2069      */
   2070     public void onMMIDone(MmiCode mmi) {
   2071 
   2072         /* Only notify complete if it's on the pending list.
   2073          * Otherwise, it's already been handled (eg, previously canceled).
   2074          * The exception is cancellation of an incoming USSD-REQUEST, which is
   2075          * not on the list.
   2076          */
   2077         if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
   2078                 ((GsmMmiCode)mmi).isSsInfo()))) {
   2079 
   2080             ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
   2081             if (receiverCallback != null) {
   2082                 Rlog.i(LOG_TAG, "onMMIDone: invoking callback: " + mmi);
   2083                 int returnCode = (mmi.getState() ==  MmiCode.State.COMPLETE) ?
   2084                     TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
   2085                 sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode,
   2086                         receiverCallback );
   2087             } else {
   2088                 Rlog.i(LOG_TAG, "onMMIDone: notifying registrants: " + mmi);
   2089                 mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
   2090             }
   2091         } else {
   2092             Rlog.i(LOG_TAG, "onMMIDone: invalid response or already handled; ignoring: " + mmi);
   2093         }
   2094     }
   2095 
   2096     public boolean supports3gppCallForwardingWhileRoaming() {
   2097         CarrierConfigManager configManager = (CarrierConfigManager)
   2098                 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
   2099         PersistableBundle b = configManager.getConfig();
   2100         if (b != null) {
   2101             return b.getBoolean(
   2102                     CarrierConfigManager.KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
   2103         } else {
   2104             // Default value set in CarrierConfigManager
   2105             return true;
   2106         }
   2107     }
   2108 
   2109     private void onNetworkInitiatedUssd(MmiCode mmi) {
   2110         Rlog.v(LOG_TAG, "onNetworkInitiatedUssd: mmi=" + mmi);
   2111         mMmiCompleteRegistrants.notifyRegistrants(
   2112             new AsyncResult(null, mmi, null));
   2113     }
   2114 
   2115     /** ussdMode is one of CommandsInterface.USSD_MODE_* */
   2116     private void onIncomingUSSD (int ussdMode, String ussdMessage) {
   2117         if (!isPhoneTypeGsm()) {
   2118             loge("onIncomingUSSD: not expected on GSM");
   2119         }
   2120         boolean isUssdError;
   2121         boolean isUssdRequest;
   2122         boolean isUssdRelease;
   2123 
   2124         isUssdRequest
   2125             = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
   2126 
   2127         isUssdError
   2128             = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
   2129                 && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
   2130 
   2131         isUssdRelease = (ussdMode == CommandsInterface.USSD_MODE_NW_RELEASE);
   2132 
   2133 
   2134         // See comments in GsmMmiCode.java
   2135         // USSD requests aren't finished until one
   2136         // of these two events happen
   2137         GsmMmiCode found = null;
   2138         for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
   2139             if(((GsmMmiCode)mPendingMMIs.get(i)).isPendingUSSD()) {
   2140                 found = (GsmMmiCode)mPendingMMIs.get(i);
   2141                 break;
   2142             }
   2143         }
   2144 
   2145         if (found != null) {
   2146             // Complete pending USSD
   2147 
   2148             if (isUssdRelease) {
   2149                 found.onUssdRelease();
   2150             } else if (isUssdError) {
   2151                 found.onUssdFinishedError();
   2152             } else {
   2153                 found.onUssdFinished(ussdMessage, isUssdRequest);
   2154             }
   2155         } else if (!isUssdError && ussdMessage != null) {
   2156             // pending USSD not found
   2157             // The network may initiate its own USSD request
   2158 
   2159             // ignore everything that isnt a Notify or a Request
   2160             // also, discard if there is no message to present
   2161             GsmMmiCode mmi;
   2162             mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
   2163                                                    isUssdRequest,
   2164                                                    GsmCdmaPhone.this,
   2165                                                    mUiccApplication.get());
   2166             onNetworkInitiatedUssd(mmi);
   2167         }
   2168     }
   2169 
   2170     /**
   2171      * Make sure the network knows our preferred setting.
   2172      */
   2173     private void syncClirSetting() {
   2174         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   2175         int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1);
   2176         Rlog.i(LOG_TAG, "syncClirSetting: " + CLIR_KEY + getPhoneId() + "=" + clirSetting);
   2177         if (clirSetting >= 0) {
   2178             mCi.setCLIR(clirSetting, null);
   2179         }
   2180     }
   2181 
   2182     private void handleRadioAvailable() {
   2183         mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
   2184 
   2185         mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
   2186         mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
   2187         startLceAfterRadioIsAvailable();
   2188     }
   2189 
   2190     private void handleRadioOn() {
   2191         /* Proactively query voice radio technologies */
   2192         mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
   2193 
   2194         if (!isPhoneTypeGsm()) {
   2195             mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
   2196         }
   2197 
   2198         // If this is on APM off, SIM may already be loaded. Send setPreferredNetworkType
   2199         // request to RIL to preserve user setting across APM toggling
   2200         setPreferredNetworkTypeIfSimLoaded();
   2201     }
   2202 
   2203     private void handleRadioOffOrNotAvailable() {
   2204         if (isPhoneTypeGsm()) {
   2205             // Some MMI requests (eg USSD) are not completed
   2206             // within the course of a CommandsInterface request
   2207             // If the radio shuts off or resets while one of these
   2208             // is pending, we need to clean up.
   2209 
   2210             for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
   2211                 if (((GsmMmiCode) mPendingMMIs.get(i)).isPendingUSSD()) {
   2212                     ((GsmMmiCode) mPendingMMIs.get(i)).onUssdFinishedError();
   2213                 }
   2214             }
   2215         }
   2216         mRadioOffOrNotAvailableRegistrants.notifyRegistrants();
   2217     }
   2218 
   2219     @Override
   2220     public void handleMessage(Message msg) {
   2221         AsyncResult ar;
   2222         Message onComplete;
   2223 
   2224         switch (msg.what) {
   2225             case EVENT_RADIO_AVAILABLE: {
   2226                 handleRadioAvailable();
   2227             }
   2228             break;
   2229 
   2230             case EVENT_GET_DEVICE_IDENTITY_DONE:{
   2231                 ar = (AsyncResult)msg.obj;
   2232 
   2233                 if (ar.exception != null) {
   2234                     break;
   2235                 }
   2236                 String[] respId = (String[])ar.result;
   2237                 mImei = respId[0];
   2238                 mImeiSv = respId[1];
   2239                 mEsn  =  respId[2];
   2240                 mMeid =  respId[3];
   2241             }
   2242             break;
   2243 
   2244             case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
   2245                 handleEnterEmergencyCallbackMode(msg);
   2246             }
   2247             break;
   2248 
   2249             case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
   2250                 handleExitEmergencyCallbackMode(msg);
   2251             }
   2252             break;
   2253 
   2254             case EVENT_MODEM_RESET: {
   2255                 logd("Event EVENT_MODEM_RESET Received" + " isInEcm = " + isInEcm()
   2256                         + " isPhoneTypeGsm = " + isPhoneTypeGsm() + " mImsPhone = " + mImsPhone);
   2257                 if (isInEcm()) {
   2258                     if (isPhoneTypeGsm()) {
   2259                         if (mImsPhone != null) {
   2260                             mImsPhone.handleExitEmergencyCallbackMode();
   2261                         }
   2262                     } else {
   2263                         handleExitEmergencyCallbackMode(msg);
   2264                     }
   2265                 }
   2266             }
   2267             break;
   2268 
   2269             case EVENT_RUIM_RECORDS_LOADED:
   2270                 logd("Event EVENT_RUIM_RECORDS_LOADED Received");
   2271                 updateCurrentCarrierInProvider();
   2272                 break;
   2273 
   2274             case EVENT_RADIO_ON:
   2275                 logd("Event EVENT_RADIO_ON Received");
   2276                 handleRadioOn();
   2277                 break;
   2278 
   2279             case EVENT_RIL_CONNECTED:
   2280                 ar = (AsyncResult) msg.obj;
   2281                 if (ar.exception == null && ar.result != null) {
   2282                     mRilVersion = (Integer) ar.result;
   2283                 } else {
   2284                     logd("Unexpected exception on EVENT_RIL_CONNECTED");
   2285                     mRilVersion = -1;
   2286                 }
   2287                 break;
   2288 
   2289             case EVENT_VOICE_RADIO_TECH_CHANGED:
   2290             case EVENT_REQUEST_VOICE_RADIO_TECH_DONE:
   2291                 String what = (msg.what == EVENT_VOICE_RADIO_TECH_CHANGED) ?
   2292                         "EVENT_VOICE_RADIO_TECH_CHANGED" : "EVENT_REQUEST_VOICE_RADIO_TECH_DONE";
   2293                 ar = (AsyncResult) msg.obj;
   2294                 if (ar.exception == null) {
   2295                     if ((ar.result != null) && (((int[]) ar.result).length != 0)) {
   2296                         int newVoiceTech = ((int[]) ar.result)[0];
   2297                         logd(what + ": newVoiceTech=" + newVoiceTech);
   2298                         phoneObjectUpdater(newVoiceTech);
   2299                     } else {
   2300                         loge(what + ": has no tech!");
   2301                     }
   2302                 } else {
   2303                     loge(what + ": exception=" + ar.exception);
   2304                 }
   2305                 break;
   2306 
   2307             case EVENT_UPDATE_PHONE_OBJECT:
   2308                 phoneObjectUpdater(msg.arg1);
   2309                 break;
   2310 
   2311             case EVENT_CARRIER_CONFIG_CHANGED:
   2312                 // Only check for the voice radio tech if it not going to be updated by the voice
   2313                 // registration changes.
   2314                 if (!mContext.getResources().getBoolean(com.android.internal.R.bool.
   2315                         config_switch_phone_on_voice_reg_state_change)) {
   2316                     mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
   2317                 }
   2318                 // Force update IMS service if it is available, if it isn't the config will be
   2319                 // updated when ImsPhoneCallTracker opens a connection.
   2320                 ImsManager imsManager = ImsManager.getInstance(mContext, mPhoneId);
   2321                 if (imsManager.isServiceAvailable()) {
   2322                     imsManager.updateImsServiceConfig(true);
   2323                 } else {
   2324                     logd("ImsManager is not available to update CarrierConfig.");
   2325                 }
   2326 
   2327                 // Update broadcastEmergencyCallStateChanges
   2328                 CarrierConfigManager configMgr = (CarrierConfigManager)
   2329                         getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
   2330                 PersistableBundle b = configMgr.getConfigForSubId(getSubId());
   2331                 if (b != null) {
   2332                     boolean broadcastEmergencyCallStateChanges = b.getBoolean(
   2333                             CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL);
   2334                     logd("broadcastEmergencyCallStateChanges = " +
   2335                             broadcastEmergencyCallStateChanges);
   2336                     setBroadcastEmergencyCallStateChanges(broadcastEmergencyCallStateChanges);
   2337                 } else {
   2338                     loge("didn't get broadcastEmergencyCallStateChanges from carrier config");
   2339                 }
   2340 
   2341                 // Changing the cdma roaming settings based carrier config.
   2342                 if (b != null) {
   2343                     int config_cdma_roaming_mode = b.getInt(
   2344                             CarrierConfigManager.KEY_CDMA_ROAMING_MODE_INT);
   2345                     int current_cdma_roaming_mode =
   2346                             Settings.Global.getInt(getContext().getContentResolver(),
   2347                             Settings.Global.CDMA_ROAMING_MODE,
   2348                             TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
   2349                     switch (config_cdma_roaming_mode) {
   2350                         // Carrier's cdma_roaming_mode will overwrite the user's previous settings
   2351                         // Keep the user's previous setting in global variable which will be used
   2352                         // when carrier's setting is turn off.
   2353                         case TelephonyManager.CDMA_ROAMING_MODE_HOME:
   2354                         case TelephonyManager.CDMA_ROAMING_MODE_AFFILIATED:
   2355                         case TelephonyManager.CDMA_ROAMING_MODE_ANY:
   2356                             logd("cdma_roaming_mode is going to changed to "
   2357                                     + config_cdma_roaming_mode);
   2358                             setCdmaRoamingPreference(config_cdma_roaming_mode,
   2359                                     obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
   2360                             break;
   2361 
   2362                         // When carrier's setting is turn off, change the cdma_roaming_mode to the
   2363                         // previous user's setting
   2364                         case TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT:
   2365                             if (current_cdma_roaming_mode != config_cdma_roaming_mode) {
   2366                                 logd("cdma_roaming_mode is going to changed to "
   2367                                         + current_cdma_roaming_mode);
   2368                                 setCdmaRoamingPreference(current_cdma_roaming_mode,
   2369                                         obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
   2370                             }
   2371 
   2372                         default:
   2373                             loge("Invalid cdma_roaming_mode settings: "
   2374                                     + config_cdma_roaming_mode);
   2375                     }
   2376                 } else {
   2377                     loge("didn't get the cdma_roaming_mode changes from the carrier config.");
   2378                 }
   2379 
   2380                 // Load the ERI based on carrier config. Carrier might have their specific ERI.
   2381                 prepareEri();
   2382                 mSST.pollState();
   2383 
   2384                 break;
   2385 
   2386             case EVENT_SET_ROAMING_PREFERENCE_DONE:
   2387                 logd("cdma_roaming_mode change is done");
   2388                 break;
   2389 
   2390             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
   2391                 logd("EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED");
   2392                 mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
   2393                 break;
   2394 
   2395             case EVENT_REGISTERED_TO_NETWORK:
   2396                 logd("Event EVENT_REGISTERED_TO_NETWORK Received");
   2397                 if (isPhoneTypeGsm()) {
   2398                     syncClirSetting();
   2399                 }
   2400                 break;
   2401 
   2402             case EVENT_SIM_RECORDS_LOADED:
   2403                 updateCurrentCarrierInProvider();
   2404 
   2405                 // Check if this is a different SIM than the previous one. If so unset the
   2406                 // voice mail number.
   2407                 String imsi = getVmSimImsi();
   2408                 String imsiFromSIM = getSubscriberId();
   2409                 if ((!isPhoneTypeGsm() || imsi != null) && imsiFromSIM != null
   2410                         && !imsiFromSIM.equals(imsi)) {
   2411                     storeVoiceMailNumber(null);
   2412                     setVmSimImsi(null);
   2413                 }
   2414 
   2415                 mSimRecordsLoadedRegistrants.notifyRegistrants();
   2416                 break;
   2417 
   2418             case EVENT_GET_BASEBAND_VERSION_DONE:
   2419                 ar = (AsyncResult)msg.obj;
   2420 
   2421                 if (ar.exception != null) {
   2422                     break;
   2423                 }
   2424 
   2425                 if (DBG) logd("Baseband version: " + ar.result);
   2426                 TelephonyManager.from(mContext).setBasebandVersionForPhone(getPhoneId(),
   2427                         (String)ar.result);
   2428             break;
   2429 
   2430             case EVENT_GET_IMEI_DONE:
   2431                 ar = (AsyncResult)msg.obj;
   2432 
   2433                 if (ar.exception != null) {
   2434                     break;
   2435                 }
   2436 
   2437                 mImei = (String)ar.result;
   2438             break;
   2439 
   2440             case EVENT_GET_IMEISV_DONE:
   2441                 ar = (AsyncResult)msg.obj;
   2442 
   2443                 if (ar.exception != null) {
   2444                     break;
   2445                 }
   2446 
   2447                 mImeiSv = (String)ar.result;
   2448             break;
   2449 
   2450             case EVENT_USSD:
   2451                 ar = (AsyncResult)msg.obj;
   2452 
   2453                 String[] ussdResult = (String[]) ar.result;
   2454 
   2455                 if (ussdResult.length > 1) {
   2456                     try {
   2457                         onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
   2458                     } catch (NumberFormatException e) {
   2459                         Rlog.w(LOG_TAG, "error parsing USSD");
   2460                     }
   2461                 }
   2462             break;
   2463 
   2464             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: {
   2465                 logd("Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
   2466                 handleRadioOffOrNotAvailable();
   2467                 break;
   2468             }
   2469 
   2470             case EVENT_SSN:
   2471                 logd("Event EVENT_SSN Received");
   2472                 if (isPhoneTypeGsm()) {
   2473                     ar = (AsyncResult) msg.obj;
   2474                     SuppServiceNotification not = (SuppServiceNotification) ar.result;
   2475                     mSsnRegistrants.notifyRegistrants(ar);
   2476                 }
   2477                 break;
   2478 
   2479             case EVENT_SET_CALL_FORWARD_DONE:
   2480                 ar = (AsyncResult)msg.obj;
   2481                 IccRecords r = mIccRecords.get();
   2482                 Cfu cfu = (Cfu) ar.userObj;
   2483                 if (ar.exception == null && r != null) {
   2484                     setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
   2485                 }
   2486                 if (cfu.mOnComplete != null) {
   2487                     AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception);
   2488                     cfu.mOnComplete.sendToTarget();
   2489                 }
   2490                 break;
   2491 
   2492             case EVENT_SET_VM_NUMBER_DONE:
   2493                 ar = (AsyncResult)msg.obj;
   2494                 if ((isPhoneTypeGsm() && IccVmNotSupportedException.class.isInstance(ar.exception)) ||
   2495                         (!isPhoneTypeGsm() && IccException.class.isInstance(ar.exception))){
   2496                     storeVoiceMailNumber(mVmNumber);
   2497                     ar.exception = null;
   2498                 }
   2499                 onComplete = (Message) ar.userObj;
   2500                 if (onComplete != null) {
   2501                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
   2502                     onComplete.sendToTarget();
   2503                 }
   2504                 break;
   2505 
   2506 
   2507             case EVENT_GET_CALL_FORWARD_DONE:
   2508                 ar = (AsyncResult)msg.obj;
   2509                 if (ar.exception == null) {
   2510                     handleCfuQueryResult((CallForwardInfo[])ar.result);
   2511                 }
   2512                 onComplete = (Message) ar.userObj;
   2513                 if (onComplete != null) {
   2514                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
   2515                     onComplete.sendToTarget();
   2516                 }
   2517                 break;
   2518 
   2519             case EVENT_SET_NETWORK_AUTOMATIC:
   2520                 // Automatic network selection from EF_CSP SIM record
   2521                 ar = (AsyncResult) msg.obj;
   2522                 if (mSST.mSS.getIsManualSelection()) {
   2523                     setNetworkSelectionModeAutomatic((Message) ar.result);
   2524                     logd("SET_NETWORK_SELECTION_AUTOMATIC: set to automatic");
   2525                 } else {
   2526                     // prevent duplicate request which will push current PLMN to low priority
   2527                     logd("SET_NETWORK_SELECTION_AUTOMATIC: already automatic, ignore");
   2528                 }
   2529                 break;
   2530 
   2531             case EVENT_ICC_RECORD_EVENTS:
   2532                 ar = (AsyncResult)msg.obj;
   2533                 processIccRecordEvents((Integer)ar.result);
   2534                 break;
   2535 
   2536             case EVENT_SET_CLIR_COMPLETE:
   2537                 ar = (AsyncResult)msg.obj;
   2538                 if (ar.exception == null) {
   2539                     saveClirSetting(msg.arg1);
   2540                 }
   2541                 onComplete = (Message) ar.userObj;
   2542                 if (onComplete != null) {
   2543                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
   2544                     onComplete.sendToTarget();
   2545                 }
   2546                 break;
   2547 
   2548             case EVENT_SS:
   2549                 ar = (AsyncResult)msg.obj;
   2550                 logd("Event EVENT_SS received");
   2551                 if (isPhoneTypeGsm()) {
   2552                     // SS data is already being handled through MMI codes.
   2553                     // So, this result if processed as MMI response would help
   2554                     // in re-using the existing functionality.
   2555                     GsmMmiCode mmi = new GsmMmiCode(this, mUiccApplication.get());
   2556                     mmi.processSsData(ar);
   2557                 }
   2558                 break;
   2559 
   2560             case EVENT_GET_RADIO_CAPABILITY:
   2561                 ar = (AsyncResult) msg.obj;
   2562                 RadioCapability rc = (RadioCapability) ar.result;
   2563                 if (ar.exception != null) {
   2564                     Rlog.d(LOG_TAG, "get phone radio capability fail, no need to change " +
   2565                             "mRadioCapability");
   2566                 } else {
   2567                     radioCapabilityUpdated(rc);
   2568                 }
   2569                 Rlog.d(LOG_TAG, "EVENT_GET_RADIO_CAPABILITY: phone rc: " + rc);
   2570                 break;
   2571 
   2572             default:
   2573                 super.handleMessage(msg);
   2574         }
   2575     }
   2576 
   2577     public UiccCardApplication getUiccCardApplication() {
   2578         if (isPhoneTypeGsm()) {
   2579             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP);
   2580         } else {
   2581             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
   2582         }
   2583     }
   2584 
   2585     // todo: check if ICC availability needs to be handled here. mSimRecords should not be needed
   2586     // now because APIs can be called directly on UiccProfile, and that should handle the requests
   2587     // correctly based on supported apps, voice RAT, etc.
   2588     @Override
   2589     protected void onUpdateIccAvailability() {
   2590         if (mUiccController == null ) {
   2591             return;
   2592         }
   2593 
   2594         UiccCardApplication newUiccApplication = null;
   2595 
   2596         // Update mIsimUiccRecords
   2597         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
   2598             newUiccApplication =
   2599                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS);
   2600             IsimUiccRecords newIsimUiccRecords = null;
   2601 
   2602             if (newUiccApplication != null) {
   2603                 newIsimUiccRecords = (IsimUiccRecords) newUiccApplication.getIccRecords();
   2604                 if (DBG) logd("New ISIM application found");
   2605             }
   2606             mIsimUiccRecords = newIsimUiccRecords;
   2607         }
   2608 
   2609         // Update mSimRecords
   2610         if (mSimRecords != null) {
   2611             mSimRecords.unregisterForRecordsLoaded(this);
   2612         }
   2613         if (isPhoneTypeCdmaLte() || isPhoneTypeCdma()) {
   2614             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
   2615                     UiccController.APP_FAM_3GPP);
   2616             SIMRecords newSimRecords = null;
   2617             if (newUiccApplication != null) {
   2618                 newSimRecords = (SIMRecords) newUiccApplication.getIccRecords();
   2619             }
   2620             mSimRecords = newSimRecords;
   2621             if (mSimRecords != null) {
   2622                 mSimRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
   2623             }
   2624         } else {
   2625             mSimRecords = null;
   2626         }
   2627 
   2628         // Update mIccRecords, mUiccApplication, mIccPhoneBookIntManager
   2629         newUiccApplication = getUiccCardApplication();
   2630         if (!isPhoneTypeGsm() && newUiccApplication == null) {
   2631             logd("can't find 3GPP2 application; trying APP_FAM_3GPP");
   2632             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
   2633                     UiccController.APP_FAM_3GPP);
   2634         }
   2635 
   2636         UiccCardApplication app = mUiccApplication.get();
   2637         if (app != newUiccApplication) {
   2638             if (app != null) {
   2639                 if (DBG) logd("Removing stale icc objects.");
   2640                 if (mIccRecords.get() != null) {
   2641                     unregisterForIccRecordEvents();
   2642                     mIccPhoneBookIntManager.updateIccRecords(null);
   2643                 }
   2644                 mIccRecords.set(null);
   2645                 mUiccApplication.set(null);
   2646             }
   2647             if (newUiccApplication != null) {
   2648                 if (DBG) {
   2649                     logd("New Uicc application found. type = " + newUiccApplication.getType());
   2650                 }
   2651                 mUiccApplication.set(newUiccApplication);
   2652                 mIccRecords.set(newUiccApplication.getIccRecords());
   2653                 registerForIccRecordEvents();
   2654                 mIccPhoneBookIntManager.updateIccRecords(mIccRecords.get());
   2655             }
   2656         }
   2657     }
   2658 
   2659     private void processIccRecordEvents(int eventCode) {
   2660         switch (eventCode) {
   2661             case IccRecords.EVENT_CFI:
   2662                 logi("processIccRecordEvents: EVENT_CFI");
   2663                 notifyCallForwardingIndicator();
   2664                 break;
   2665         }
   2666     }
   2667 
   2668     /**
   2669      * Sets the "current" field in the telephony provider according to the SIM's operator
   2670      *
   2671      * @return true for success; false otherwise.
   2672      */
   2673     @Override
   2674     public boolean updateCurrentCarrierInProvider() {
   2675         long currentDds = SubscriptionManager.getDefaultDataSubscriptionId();
   2676         String operatorNumeric = getOperatorNumeric();
   2677 
   2678         logd("updateCurrentCarrierInProvider: mSubId = " + getSubId()
   2679                 + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric);
   2680 
   2681         if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) {
   2682             try {
   2683                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
   2684                 ContentValues map = new ContentValues();
   2685                 map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
   2686                 mContext.getContentResolver().insert(uri, map);
   2687                 return true;
   2688             } catch (SQLException e) {
   2689                 Rlog.e(LOG_TAG, "Can't store current operator", e);
   2690             }
   2691         }
   2692         return false;
   2693     }
   2694 
   2695     //CDMA
   2696     /**
   2697      * Sets the "current" field in the telephony provider according to the
   2698      * build-time operator numeric property
   2699      *
   2700      * @return true for success; false otherwise.
   2701      */
   2702     private boolean updateCurrentCarrierInProvider(String operatorNumeric) {
   2703         if (isPhoneTypeCdma()
   2704                 || (isPhoneTypeCdmaLte() && mUiccController.getUiccCardApplication(mPhoneId,
   2705                         UiccController.APP_FAM_3GPP) == null)) {
   2706             logd("CDMAPhone: updateCurrentCarrierInProvider called");
   2707             if (!TextUtils.isEmpty(operatorNumeric)) {
   2708                 try {
   2709                     Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
   2710                     ContentValues map = new ContentValues();
   2711                     map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
   2712                     logd("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric);
   2713                     getContext().getContentResolver().insert(uri, map);
   2714 
   2715                     // Updates MCC MNC device configuration information
   2716                     logd("update mccmnc=" + operatorNumeric);
   2717                     MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
   2718 
   2719                     return true;
   2720                 } catch (SQLException e) {
   2721                     Rlog.e(LOG_TAG, "Can't store current operator", e);
   2722                 }
   2723             }
   2724             return false;
   2725         } else { // isPhoneTypeCdmaLte()
   2726             if (DBG) logd("updateCurrentCarrierInProvider not updated X retVal=" + true);
   2727             return true;
   2728         }
   2729     }
   2730 
   2731     private void handleCfuQueryResult(CallForwardInfo[] infos) {
   2732         IccRecords r = mIccRecords.get();
   2733         if (r != null) {
   2734             if (infos == null || infos.length == 0) {
   2735                 // Assume the default is not active
   2736                 // Set unconditional CFF in SIM to false
   2737                 setVoiceCallForwardingFlag(1, false, null);
   2738             } else {
   2739                 for (int i = 0, s = infos.length; i < s; i++) {
   2740                     if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
   2741                         setVoiceCallForwardingFlag(1, (infos[i].status == 1),
   2742                             infos[i].number);
   2743                         // should only have the one
   2744                         break;
   2745                     }
   2746                 }
   2747             }
   2748         }
   2749     }
   2750 
   2751     /**
   2752      * Retrieves the IccPhoneBookInterfaceManager of the GsmCdmaPhone
   2753      */
   2754     @Override
   2755     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
   2756         return mIccPhoneBookIntManager;
   2757     }
   2758 
   2759     //CDMA
   2760     public void registerForEriFileLoaded(Handler h, int what, Object obj) {
   2761         Registrant r = new Registrant (h, what, obj);
   2762         mEriFileLoadedRegistrants.add(r);
   2763     }
   2764 
   2765     //CDMA
   2766     public void unregisterForEriFileLoaded(Handler h) {
   2767         mEriFileLoadedRegistrants.remove(h);
   2768     }
   2769 
   2770     //CDMA
   2771     public void prepareEri() {
   2772         if (mEriManager == null) {
   2773             Rlog.e(LOG_TAG, "PrepareEri: Trying to access stale objects");
   2774             return;
   2775         }
   2776         mEriManager.loadEriFile();
   2777         if(mEriManager.isEriFileLoaded()) {
   2778             // when the ERI file is loaded
   2779             logd("ERI read, notify registrants");
   2780             mEriFileLoadedRegistrants.notifyRegistrants();
   2781         }
   2782     }
   2783 
   2784     //CDMA
   2785     public boolean isEriFileLoaded() {
   2786         return mEriManager.isEriFileLoaded();
   2787     }
   2788 
   2789 
   2790     /**
   2791      * Activate or deactivate cell broadcast SMS.
   2792      *
   2793      * @param activate 0 = activate, 1 = deactivate
   2794      * @param response Callback message is empty on completion
   2795      */
   2796     @Override
   2797     public void activateCellBroadcastSms(int activate, Message response) {
   2798         loge("[GsmCdmaPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
   2799         response.sendToTarget();
   2800     }
   2801 
   2802     /**
   2803      * Query the current configuration of cdma cell broadcast SMS.
   2804      *
   2805      * @param response Callback message is empty on completion
   2806      */
   2807     @Override
   2808     public void getCellBroadcastSmsConfig(Message response) {
   2809         loge("[GsmCdmaPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
   2810         response.sendToTarget();
   2811     }
   2812 
   2813     /**
   2814      * Configure cdma cell broadcast SMS.
   2815      *
   2816      * @param response Callback message is empty on completion
   2817      */
   2818     @Override
   2819     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
   2820         loge("[GsmCdmaPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
   2821         response.sendToTarget();
   2822     }
   2823 
   2824     /**
   2825      * Returns true if OTA Service Provisioning needs to be performed.
   2826      */
   2827     @Override
   2828     public boolean needsOtaServiceProvisioning() {
   2829         if (isPhoneTypeGsm()) {
   2830             return false;
   2831         } else {
   2832             return mSST.getOtasp() != TelephonyManager.OTASP_NOT_NEEDED;
   2833         }
   2834     }
   2835 
   2836     @Override
   2837     public boolean isCspPlmnEnabled() {
   2838         IccRecords r = mIccRecords.get();
   2839         return (r != null) ? r.isCspPlmnEnabled() : false;
   2840     }
   2841 
   2842     /**
   2843      * Whether manual select is now allowed and we should set
   2844      * to auto network select mode.
   2845      */
   2846     public boolean shouldForceAutoNetworkSelect() {
   2847 
   2848         int nwMode = Phone.PREFERRED_NT_MODE;
   2849         int subId = getSubId();
   2850 
   2851         // If it's invalid subId, we shouldn't force to auto network select mode.
   2852         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
   2853             return false;
   2854         }
   2855 
   2856         nwMode = android.provider.Settings.Global.getInt(mContext.getContentResolver(),
   2857                     android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, nwMode);
   2858 
   2859         logd("shouldForceAutoNetworkSelect in mode = " + nwMode);
   2860         /*
   2861          *  For multimode targets in global mode manual network
   2862          *  selection is disallowed. So we should force auto select mode.
   2863          */
   2864         if (isManualSelProhibitedInGlobalMode()
   2865                 && ((nwMode == Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
   2866                         || (nwMode == Phone.NT_MODE_GLOBAL)) ){
   2867             logd("Should force auto network select mode = " + nwMode);
   2868             return true;
   2869         } else {
   2870             logd("Should not force auto network select mode = " + nwMode);
   2871         }
   2872 
   2873         /*
   2874          *  Single mode phone with - GSM network modes/global mode
   2875          *  LTE only for 3GPP
   2876          *  LTE centric + 3GPP Legacy
   2877          *  Note: the actual enabling/disabling manual selection for these
   2878          *  cases will be controlled by csp
   2879          */
   2880         return false;
   2881     }
   2882 
   2883     private boolean isManualSelProhibitedInGlobalMode() {
   2884         boolean isProhibited = false;
   2885         final String configString = getContext().getResources().getString(com.android.internal.
   2886                 R.string.prohibit_manual_network_selection_in_gobal_mode);
   2887 
   2888         if (!TextUtils.isEmpty(configString)) {
   2889             String[] configArray = configString.split(";");
   2890 
   2891             if (configArray != null &&
   2892                     ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true")) ||
   2893                         (configArray.length == 2 && !TextUtils.isEmpty(configArray[1]) &&
   2894                             configArray[0].equalsIgnoreCase("true") &&
   2895                             isMatchGid(configArray[1])))) {
   2896                             isProhibited = true;
   2897             }
   2898         }
   2899         logd("isManualNetSelAllowedInGlobal in current carrier is " + isProhibited);
   2900         return isProhibited;
   2901     }
   2902 
   2903     private void registerForIccRecordEvents() {
   2904         IccRecords r = mIccRecords.get();
   2905         if (r == null) {
   2906             return;
   2907         }
   2908         if (isPhoneTypeGsm()) {
   2909             r.registerForNetworkSelectionModeAutomatic(
   2910                     this, EVENT_SET_NETWORK_AUTOMATIC, null);
   2911             r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
   2912             r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
   2913         } else {
   2914             r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
   2915             if (isPhoneTypeCdmaLte()) {
   2916                 // notify simRecordsLoaded registrants for cdmaLte phone
   2917                 r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
   2918             }
   2919         }
   2920     }
   2921 
   2922     private void unregisterForIccRecordEvents() {
   2923         IccRecords r = mIccRecords.get();
   2924         if (r == null) {
   2925             return;
   2926         }
   2927         r.unregisterForNetworkSelectionModeAutomatic(this);
   2928         r.unregisterForRecordsEvents(this);
   2929         r.unregisterForRecordsLoaded(this);
   2930     }
   2931 
   2932     @Override
   2933     public void exitEmergencyCallbackMode() {
   2934         if (DBG) {
   2935             Rlog.d(LOG_TAG, "exitEmergencyCallbackMode: mImsPhone=" + mImsPhone
   2936                     + " isPhoneTypeGsm=" + isPhoneTypeGsm());
   2937         }
   2938         if (isPhoneTypeGsm()) {
   2939             if (mImsPhone != null) {
   2940                 mImsPhone.exitEmergencyCallbackMode();
   2941             }
   2942         } else {
   2943             if (mWakeLock.isHeld()) {
   2944                 mWakeLock.release();
   2945             }
   2946             // Send a message which will invoke handleExitEmergencyCallbackMode
   2947             mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
   2948         }
   2949     }
   2950 
   2951     //CDMA
   2952     private void handleEnterEmergencyCallbackMode(Message msg) {
   2953         if (DBG) {
   2954             Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode, isInEcm()="
   2955                     + isInEcm());
   2956         }
   2957         // if phone is not in Ecm mode, and it's changed to Ecm mode
   2958         if (!isInEcm()) {
   2959             setIsInEcm(true);
   2960 
   2961             // notify change
   2962             sendEmergencyCallbackModeChange();
   2963 
   2964             // Post this runnable so we will automatically exit
   2965             // if no one invokes exitEmergencyCallbackMode() directly.
   2966             long delayInMillis = SystemProperties.getLong(
   2967                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
   2968             postDelayed(mExitEcmRunnable, delayInMillis);
   2969             // We don't want to go to sleep while in Ecm
   2970             mWakeLock.acquire();
   2971         }
   2972     }
   2973 
   2974     //CDMA
   2975     private void handleExitEmergencyCallbackMode(Message msg) {
   2976         AsyncResult ar = (AsyncResult)msg.obj;
   2977         if (DBG) {
   2978             Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , isInEcm="
   2979                     + ar.exception + isInEcm());
   2980         }
   2981         // Remove pending exit Ecm runnable, if any
   2982         removeCallbacks(mExitEcmRunnable);
   2983 
   2984         if (mEcmExitRespRegistrant != null) {
   2985             mEcmExitRespRegistrant.notifyRegistrant(ar);
   2986         }
   2987         // if exiting ecm success
   2988         if (ar.exception == null) {
   2989             if (isInEcm()) {
   2990                 setIsInEcm(false);
   2991             }
   2992 
   2993             // release wakeLock
   2994             if (mWakeLock.isHeld()) {
   2995                 mWakeLock.release();
   2996             }
   2997 
   2998             // send an Intent
   2999             sendEmergencyCallbackModeChange();
   3000             // Re-initiate data connection
   3001             mDcTracker.setInternalDataEnabled(true);
   3002             notifyEmergencyCallRegistrants(false);
   3003         }
   3004     }
   3005 
   3006     //CDMA
   3007     public void notifyEmergencyCallRegistrants(boolean started) {
   3008         mEmergencyCallToggledRegistrants.notifyResult(started ? 1 : 0);
   3009     }
   3010 
   3011     //CDMA
   3012     /**
   3013      * Handle to cancel or restart Ecm timer in emergency call back mode
   3014      * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
   3015      * otherwise, restart Ecm timer and notify apps the timer is restarted.
   3016      */
   3017     public void handleTimerInEmergencyCallbackMode(int action) {
   3018         switch(action) {
   3019             case CANCEL_ECM_TIMER:
   3020                 removeCallbacks(mExitEcmRunnable);
   3021                 mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE);
   3022                 break;
   3023             case RESTART_ECM_TIMER:
   3024                 long delayInMillis = SystemProperties.getLong(
   3025                         TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
   3026                 postDelayed(mExitEcmRunnable, delayInMillis);
   3027                 mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE);
   3028                 break;
   3029             default:
   3030                 Rlog.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
   3031         }
   3032     }
   3033 
   3034     //CDMA
   3035     private static final String IS683A_FEATURE_CODE = "*228";
   3036     private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
   3037     private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
   3038     private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
   3039 
   3040     private static final int IS683_CONST_800MHZ_A_BAND = 0;
   3041     private static final int IS683_CONST_800MHZ_B_BAND = 1;
   3042     private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
   3043     private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
   3044     private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
   3045     private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
   3046     private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
   3047     private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
   3048     private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
   3049 
   3050     // Define the pattern/format for carrier specified OTASP number schema.
   3051     // It separates by comma and/or whitespace.
   3052     private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
   3053 
   3054     //CDMA
   3055     private static boolean isIs683OtaSpDialStr(String dialStr) {
   3056         int sysSelCodeInt;
   3057         boolean isOtaspDialString = false;
   3058         int dialStrLen = dialStr.length();
   3059 
   3060         if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
   3061             if (dialStr.equals(IS683A_FEATURE_CODE)) {
   3062                 isOtaspDialString = true;
   3063             }
   3064         } else {
   3065             sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
   3066             switch (sysSelCodeInt) {
   3067                 case IS683_CONST_800MHZ_A_BAND:
   3068                 case IS683_CONST_800MHZ_B_BAND:
   3069                 case IS683_CONST_1900MHZ_A_BLOCK:
   3070                 case IS683_CONST_1900MHZ_B_BLOCK:
   3071                 case IS683_CONST_1900MHZ_C_BLOCK:
   3072                 case IS683_CONST_1900MHZ_D_BLOCK:
   3073                 case IS683_CONST_1900MHZ_E_BLOCK:
   3074                 case IS683_CONST_1900MHZ_F_BLOCK:
   3075                     isOtaspDialString = true;
   3076                     break;
   3077                 default:
   3078                     break;
   3079             }
   3080         }
   3081         return isOtaspDialString;
   3082     }
   3083 
   3084     //CDMA
   3085     /**
   3086      * This function extracts the system selection code from the dial string.
   3087      */
   3088     private static int extractSelCodeFromOtaSpNum(String dialStr) {
   3089         int dialStrLen = dialStr.length();
   3090         int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
   3091 
   3092         if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
   3093                 0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
   3094                 (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
   3095                         IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
   3096             // Since we checked the condition above, the system selection code
   3097             // extracted from dialStr will not cause any exception
   3098             sysSelCodeInt = Integer.parseInt (
   3099                     dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
   3100                             IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
   3101         }
   3102         if (DBG) Rlog.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
   3103         return sysSelCodeInt;
   3104     }
   3105 
   3106     //CDMA
   3107     /**
   3108      * This function checks if the system selection code extracted from
   3109      * the dial string "sysSelCodeInt' is the system selection code specified
   3110      * in the carrier ota sp number schema "sch".
   3111      */
   3112     private static boolean checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[]) {
   3113         boolean isOtaSpNum = false;
   3114         try {
   3115             // Get how many number of system selection code ranges
   3116             int selRc = Integer.parseInt(sch[1]);
   3117             for (int i = 0; i < selRc; i++) {
   3118                 if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
   3119                     int selMin = Integer.parseInt(sch[i+2]);
   3120                     int selMax = Integer.parseInt(sch[i+3]);
   3121                     // Check if the selection code extracted from the dial string falls
   3122                     // within any of the range pairs specified in the schema.
   3123                     if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
   3124                         isOtaSpNum = true;
   3125                         break;
   3126                     }
   3127                 }
   3128             }
   3129         } catch (NumberFormatException ex) {
   3130             // If the carrier ota sp number schema is not correct, we still allow dial
   3131             // and only log the error:
   3132             Rlog.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
   3133         }
   3134         return isOtaSpNum;
   3135     }
   3136 
   3137     //CDMA
   3138     /**
   3139      * The following function checks if a dial string is a carrier specified
   3140      * OTASP number or not by checking against the OTASP number schema stored
   3141      * in PROPERTY_OTASP_NUM_SCHEMA.
   3142      *
   3143      * Currently, there are 2 schemas for carriers to specify the OTASP number:
   3144      * 1) Use system selection code:
   3145      *    The schema is:
   3146      *    SELC,the # of code pairs,min1,max1,min2,max2,...
   3147      *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
   3148      *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
   3149      *
   3150      * 2) Use feature code:
   3151      *    The schema is:
   3152      *    "FC,length of feature code,feature code".
   3153      *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
   3154      *     and the code itself is "*2".
   3155      */
   3156     private boolean isCarrierOtaSpNum(String dialStr) {
   3157         boolean isOtaSpNum = false;
   3158         int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
   3159         if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
   3160             return isOtaSpNum;
   3161         }
   3162         // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
   3163         if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
   3164             Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
   3165             if (DBG) {
   3166                 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
   3167             }
   3168 
   3169             if (m.find()) {
   3170                 String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
   3171                 // If carrier uses system selection code mechanism
   3172                 if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
   3173                     if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
   3174                         isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
   3175                     } else {
   3176                         if (DBG) {
   3177                             Rlog.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
   3178                         }
   3179                     }
   3180                 } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
   3181                     int fcLen =  Integer.parseInt(sch[1]);
   3182                     String fc = sch[2];
   3183                     if (dialStr.regionMatches(0,fc,0,fcLen)) {
   3184                         isOtaSpNum = true;
   3185                     } else {
   3186                         if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
   3187                     }
   3188                 } else {
   3189                     if (DBG) {
   3190                         Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
   3191                     }
   3192                 }
   3193             } else {
   3194                 if (DBG) {
   3195                     Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
   3196                             mCarrierOtaSpNumSchema);
   3197                 }
   3198             }
   3199         } else {
   3200             if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
   3201         }
   3202         return isOtaSpNum;
   3203     }
   3204 
   3205     /**
   3206      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
   3207      * OTASP dial string.
   3208      *
   3209      * @param dialStr the number to look up.
   3210      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
   3211      */
   3212     @Override
   3213     public  boolean isOtaSpNumber(String dialStr) {
   3214         if (isPhoneTypeGsm()) {
   3215             return super.isOtaSpNumber(dialStr);
   3216         } else {
   3217             boolean isOtaSpNum = false;
   3218             String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr);
   3219             if (dialableStr != null) {
   3220                 isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
   3221                 if (isOtaSpNum == false) {
   3222                     isOtaSpNum = isCarrierOtaSpNum(dialableStr);
   3223                 }
   3224             }
   3225             if (DBG) Rlog.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
   3226             return isOtaSpNum;
   3227         }
   3228     }
   3229 
   3230     @Override
   3231     public int getCdmaEriIconIndex() {
   3232         if (isPhoneTypeGsm()) {
   3233             return super.getCdmaEriIconIndex();
   3234         } else {
   3235             return getServiceState().getCdmaEriIconIndex();
   3236         }
   3237     }
   3238 
   3239     /**
   3240      * Returns the CDMA ERI icon mode,
   3241      * 0 - ON
   3242      * 1 - FLASHING
   3243      */
   3244     @Override
   3245     public int getCdmaEriIconMode() {
   3246         if (isPhoneTypeGsm()) {
   3247             return super.getCdmaEriIconMode();
   3248         } else {
   3249             return getServiceState().getCdmaEriIconMode();
   3250         }
   3251     }
   3252 
   3253     /**
   3254      * Returns the CDMA ERI text,
   3255      */
   3256     @Override
   3257     public String getCdmaEriText() {
   3258         if (isPhoneTypeGsm()) {
   3259             return super.getCdmaEriText();
   3260         } else {
   3261             int roamInd = getServiceState().getCdmaRoamingIndicator();
   3262             int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
   3263             return mEriManager.getCdmaEriText(roamInd, defRoamInd);
   3264         }
   3265     }
   3266 
   3267     private void phoneObjectUpdater(int newVoiceRadioTech) {
   3268         logd("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech);
   3269 
   3270         // Check for a voice over lte replacement
   3271         if (ServiceState.isLte(newVoiceRadioTech)
   3272                 || (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
   3273             CarrierConfigManager configMgr = (CarrierConfigManager)
   3274                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
   3275             PersistableBundle b = configMgr.getConfigForSubId(getSubId());
   3276             if (b != null) {
   3277                 int volteReplacementRat =
   3278                         b.getInt(CarrierConfigManager.KEY_VOLTE_REPLACEMENT_RAT_INT);
   3279                 logd("phoneObjectUpdater: volteReplacementRat=" + volteReplacementRat);
   3280                 if (volteReplacementRat != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
   3281                     newVoiceRadioTech = volteReplacementRat;
   3282                 }
   3283             } else {
   3284                 loge("phoneObjectUpdater: didn't get volteReplacementRat from carrier config");
   3285             }
   3286         }
   3287 
   3288         if(mRilVersion == 6 && getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
   3289             /*
   3290              * On v6 RIL, when LTE_ON_CDMA is TRUE, always create CDMALTEPhone
   3291              * irrespective of the voice radio tech reported.
   3292              */
   3293             if (getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
   3294                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Use CDMA Phone" +
   3295                         " newVoiceRadioTech=" + newVoiceRadioTech +
   3296                         " mActivePhone=" + getPhoneName());
   3297                 return;
   3298             } else {
   3299                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Switch to CDMALTEPhone" +
   3300                         " newVoiceRadioTech=" + newVoiceRadioTech +
   3301                         " mActivePhone=" + getPhoneName());
   3302                 newVoiceRadioTech = ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT;
   3303             }
   3304         } else {
   3305 
   3306             // If the device is shutting down, then there is no need to switch to the new phone
   3307             // which might send unnecessary attach request to the modem.
   3308             if (isShuttingDown()) {
   3309                 logd("Device is shutting down. No need to switch phone now.");
   3310                 return;
   3311             }
   3312 
   3313             boolean matchCdma = ServiceState.isCdma(newVoiceRadioTech);
   3314             boolean matchGsm = ServiceState.isGsm(newVoiceRadioTech);
   3315             if ((matchCdma && getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) ||
   3316                     (matchGsm && getPhoneType() == PhoneConstants.PHONE_TYPE_GSM)) {
   3317                 // Nothing changed. Keep phone as it is.
   3318                 logd("phoneObjectUpdater: No change ignore," +
   3319                         " newVoiceRadioTech=" + newVoiceRadioTech +
   3320                         " mActivePhone=" + getPhoneName());
   3321                 return;
   3322             }
   3323             if (!matchCdma && !matchGsm) {
   3324                 loge("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech +
   3325                         " doesn't match either CDMA or GSM - error! No phone change");
   3326                 return;
   3327             }
   3328         }
   3329 
   3330         if (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
   3331             // We need some voice phone object to be active always, so never
   3332             // delete the phone without anything to replace it with!
   3333             logd("phoneObjectUpdater: Unknown rat ignore, "
   3334                     + " newVoiceRadioTech=Unknown. mActivePhone=" + getPhoneName());
   3335             return;
   3336         }
   3337 
   3338         boolean oldPowerState = false; // old power state to off
   3339         if (mResetModemOnRadioTechnologyChange) {
   3340             if (mCi.getRadioState().isOn()) {
   3341                 oldPowerState = true;
   3342                 logd("phoneObjectUpdater: Setting Radio Power to Off");
   3343                 mCi.setRadioPower(false, null);
   3344             }
   3345         }
   3346 
   3347         switchVoiceRadioTech(newVoiceRadioTech);
   3348 
   3349         if (mResetModemOnRadioTechnologyChange && oldPowerState) { // restore power state
   3350             logd("phoneObjectUpdater: Resetting Radio");
   3351             mCi.setRadioPower(oldPowerState, null);
   3352         }
   3353 
   3354         // update voice radio tech in UiccProfile
   3355         UiccProfile uiccProfile = getUiccProfile();
   3356         if (uiccProfile != null) {
   3357             uiccProfile.setVoiceRadioTech(newVoiceRadioTech);
   3358         }
   3359 
   3360         // Send an Intent to the PhoneApp that we had a radio technology change
   3361         Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
   3362         intent.putExtra(PhoneConstants.PHONE_NAME_KEY, getPhoneName());
   3363         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
   3364         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
   3365     }
   3366 
   3367     private void switchVoiceRadioTech(int newVoiceRadioTech) {
   3368 
   3369         String outgoingPhoneName = getPhoneName();
   3370 
   3371         logd("Switching Voice Phone : " + outgoingPhoneName + " >>> "
   3372                 + (ServiceState.isGsm(newVoiceRadioTech) ? "GSM" : "CDMA"));
   3373 
   3374         if (ServiceState.isCdma(newVoiceRadioTech)) {
   3375             UiccCardApplication cdmaApplication =
   3376                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
   3377             if (cdmaApplication != null && cdmaApplication.getType() == AppType.APPTYPE_RUIM) {
   3378                 switchPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
   3379             } else {
   3380                 switchPhoneType(PhoneConstants.PHONE_TYPE_CDMA_LTE);
   3381             }
   3382         } else if (ServiceState.isGsm(newVoiceRadioTech)) {
   3383             switchPhoneType(PhoneConstants.PHONE_TYPE_GSM);
   3384         } else {
   3385             loge("deleteAndCreatePhone: newVoiceRadioTech=" + newVoiceRadioTech +
   3386                     " is not CDMA or GSM (error) - aborting!");
   3387             return;
   3388         }
   3389     }
   3390 
   3391     @Override
   3392     public void setSignalStrengthReportingCriteria(int[] thresholds, int ran) {
   3393         mCi.setSignalStrengthReportingCriteria(REPORTING_HYSTERESIS_MILLIS, REPORTING_HYSTERESIS_DB,
   3394                 thresholds, ran, null);
   3395     }
   3396 
   3397     @Override
   3398     public void setLinkCapacityReportingCriteria(int[] dlThresholds, int[] ulThresholds, int ran) {
   3399         mCi.setLinkCapacityReportingCriteria(REPORTING_HYSTERESIS_MILLIS, REPORTING_HYSTERESIS_KBPS,
   3400                 REPORTING_HYSTERESIS_KBPS, dlThresholds, ulThresholds, ran, null);
   3401     }
   3402 
   3403     @Override
   3404     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
   3405         return mIccSmsInterfaceManager;
   3406     }
   3407 
   3408     @Override
   3409     public void updatePhoneObject(int voiceRadioTech) {
   3410         logd("updatePhoneObject: radioTechnology=" + voiceRadioTech);
   3411         sendMessage(obtainMessage(EVENT_UPDATE_PHONE_OBJECT, voiceRadioTech, 0, null));
   3412     }
   3413 
   3414     @Override
   3415     public void setImsRegistrationState(boolean registered) {
   3416         mSST.setImsRegistrationState(registered);
   3417     }
   3418 
   3419     @Override
   3420     public boolean getIccRecordsLoaded() {
   3421         UiccProfile uiccProfile = getUiccProfile();
   3422         return uiccProfile != null && uiccProfile.getIccRecordsLoaded();
   3423     }
   3424 
   3425     @Override
   3426     public IccCard getIccCard() {
   3427         // This function doesn't return null for backwards compatability purposes.
   3428         // To differentiate between cases where SIM is absent vs. unknown we return a dummy
   3429         // IccCard with the sim state set.
   3430         IccCard card = getUiccProfile();
   3431         if (card != null) {
   3432             return card;
   3433         } else {
   3434             UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId);
   3435             if (slot == null || slot.isStateUnknown()) {
   3436                 return new IccCard(IccCardConstants.State.UNKNOWN);
   3437             } else {
   3438                 return new IccCard(IccCardConstants.State.ABSENT);
   3439             }
   3440         }
   3441     }
   3442 
   3443     private UiccProfile getUiccProfile() {
   3444         return UiccController.getInstance().getUiccProfileForPhone(mPhoneId);
   3445     }
   3446 
   3447     @Override
   3448     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   3449         pw.println("GsmCdmaPhone extends:");
   3450         super.dump(fd, pw, args);
   3451         pw.println(" mPrecisePhoneType=" + mPrecisePhoneType);
   3452         pw.println(" mCT=" + mCT);
   3453         pw.println(" mSST=" + mSST);
   3454         pw.println(" mPendingMMIs=" + mPendingMMIs);
   3455         pw.println(" mIccPhoneBookIntManager=" + mIccPhoneBookIntManager);
   3456         if (VDBG) pw.println(" mImei=" + mImei);
   3457         if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
   3458         if (VDBG) pw.println(" mVmNumber=" + mVmNumber);
   3459         pw.println(" mCdmaSSM=" + mCdmaSSM);
   3460         pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource);
   3461         pw.println(" mEriManager=" + mEriManager);
   3462         pw.println(" mWakeLock=" + mWakeLock);
   3463         pw.println(" isInEcm()=" + isInEcm());
   3464         if (VDBG) pw.println(" mEsn=" + mEsn);
   3465         if (VDBG) pw.println(" mMeid=" + mMeid);
   3466         pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema);
   3467         if (!isPhoneTypeGsm()) {
   3468             pw.println(" getCdmaEriIconIndex()=" + getCdmaEriIconIndex());
   3469             pw.println(" getCdmaEriIconMode()=" + getCdmaEriIconMode());
   3470             pw.println(" getCdmaEriText()=" + getCdmaEriText());
   3471             pw.println(" isMinInfoReady()=" + isMinInfoReady());
   3472         }
   3473         pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
   3474         pw.flush();
   3475     }
   3476 
   3477     @Override
   3478     public boolean setOperatorBrandOverride(String brand) {
   3479         if (mUiccController == null) {
   3480             return false;
   3481         }
   3482 
   3483         UiccCard card = mUiccController.getUiccCard(getPhoneId());
   3484         if (card == null) {
   3485             return false;
   3486         }
   3487 
   3488         boolean status = card.setOperatorBrandOverride(brand);
   3489 
   3490         // Refresh.
   3491         if (status) {
   3492             IccRecords iccRecords = mIccRecords.get();
   3493             if (iccRecords != null) {
   3494                 TelephonyManager.from(mContext).setSimOperatorNameForPhone(
   3495                         getPhoneId(), iccRecords.getServiceProviderName());
   3496             }
   3497             if (mSST != null) {
   3498                 mSST.pollState();
   3499             }
   3500         }
   3501         return status;
   3502     }
   3503 
   3504     /**
   3505      * @return operator numeric.
   3506      */
   3507     private String getOperatorNumeric() {
   3508         String operatorNumeric = null;
   3509         if (isPhoneTypeGsm()) {
   3510             IccRecords r = mIccRecords.get();
   3511             if (r != null) {
   3512                 operatorNumeric = r.getOperatorNumeric();
   3513             }
   3514         } else { //isPhoneTypeCdmaLte()
   3515             IccRecords curIccRecords = null;
   3516             if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_NV) {
   3517                 operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric");
   3518             } else if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_RUIM_SIM) {
   3519                 UiccCardApplication uiccCardApplication = mUiccApplication.get();
   3520                 if (uiccCardApplication != null
   3521                         && uiccCardApplication.getType() == AppType.APPTYPE_RUIM) {
   3522                     logd("Legacy RUIM app present");
   3523                     curIccRecords = mIccRecords.get();
   3524                 } else {
   3525                     // Use sim-records for SimApp, USimApp, CSimApp and ISimApp.
   3526                     curIccRecords = mSimRecords;
   3527                 }
   3528                 if (curIccRecords != null && curIccRecords == mSimRecords) {
   3529                     operatorNumeric = curIccRecords.getOperatorNumeric();
   3530                 } else {
   3531                     curIccRecords = mIccRecords.get();
   3532                     if (curIccRecords != null && (curIccRecords instanceof RuimRecords)) {
   3533                         RuimRecords csim = (RuimRecords) curIccRecords;
   3534                         operatorNumeric = csim.getRUIMOperatorNumeric();
   3535                     }
   3536                 }
   3537             }
   3538             if (operatorNumeric == null) {
   3539                 loge("getOperatorNumeric: Cannot retrieve operatorNumeric:"
   3540                         + " mCdmaSubscriptionSource = " + mCdmaSubscriptionSource +
   3541                         " mIccRecords = " + ((curIccRecords != null) ?
   3542                         curIccRecords.getRecordsLoaded() : null));
   3543             }
   3544 
   3545             logd("getOperatorNumeric: mCdmaSubscriptionSource = " + mCdmaSubscriptionSource
   3546                     + " operatorNumeric = " + operatorNumeric);
   3547 
   3548         }
   3549         return operatorNumeric;
   3550     }
   3551 
   3552     /**
   3553      * @return The country ISO for the subscription associated with this phone.
   3554      */
   3555     public String getCountryIso() {
   3556         int subId = getSubId();
   3557         SubscriptionInfo subInfo = SubscriptionManager.from(getContext())
   3558                 .getActiveSubscriptionInfo(subId);
   3559         if (subInfo == null) {
   3560             return null;
   3561         }
   3562         return subInfo.getCountryIso().toUpperCase();
   3563     }
   3564 
   3565     public void notifyEcbmTimerReset(Boolean flag) {
   3566         mEcmTimerResetRegistrants.notifyResult(flag);
   3567     }
   3568 
   3569     /**
   3570      * Registration point for Ecm timer reset
   3571      *
   3572      * @param h handler to notify
   3573      * @param what User-defined message code
   3574      * @param obj placed in Message.obj
   3575      */
   3576     @Override
   3577     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
   3578         mEcmTimerResetRegistrants.addUnique(h, what, obj);
   3579     }
   3580 
   3581     @Override
   3582     public void unregisterForEcmTimerReset(Handler h) {
   3583         mEcmTimerResetRegistrants.remove(h);
   3584     }
   3585 
   3586     /**
   3587      * Sets the SIM voice message waiting indicator records.
   3588      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
   3589      * @param countWaiting The number of messages waiting, if known. Use
   3590      *                     -1 to indicate that an unknown number of
   3591      *                      messages are waiting
   3592      */
   3593     @Override
   3594     public void setVoiceMessageWaiting(int line, int countWaiting) {
   3595         if (isPhoneTypeGsm()) {
   3596             IccRecords r = mIccRecords.get();
   3597             if (r != null) {
   3598                 r.setVoiceMessageWaiting(line, countWaiting);
   3599             } else {
   3600                 logd("SIM Records not found, MWI not updated");
   3601             }
   3602         } else {
   3603             setVoiceMessageCount(countWaiting);
   3604         }
   3605     }
   3606 
   3607     private void logd(String s) {
   3608         Rlog.d(LOG_TAG, "[" + mPhoneId + "] " + s);
   3609     }
   3610 
   3611     private void logi(String s) {
   3612         Rlog.i(LOG_TAG, "[" + mPhoneId + "] " + s);
   3613     }
   3614 
   3615     private void loge(String s) {
   3616         Rlog.e(LOG_TAG, "[" + mPhoneId + "] " + s);
   3617     }
   3618 
   3619     @Override
   3620     public boolean isUtEnabled() {
   3621         Phone imsPhone = mImsPhone;
   3622         if (imsPhone != null) {
   3623             return imsPhone.isUtEnabled();
   3624         } else {
   3625             logd("isUtEnabled: called for GsmCdma");
   3626             return false;
   3627         }
   3628     }
   3629 
   3630     public String getDtmfToneDelayKey() {
   3631         return isPhoneTypeGsm() ?
   3632                 CarrierConfigManager.KEY_GSM_DTMF_TONE_DELAY_INT :
   3633                 CarrierConfigManager.KEY_CDMA_DTMF_TONE_DELAY_INT;
   3634     }
   3635 
   3636     @VisibleForTesting
   3637     public PowerManager.WakeLock getWakeLock() {
   3638         return mWakeLock;
   3639     }
   3640 
   3641     @Override
   3642     public int getLteOnCdmaMode() {
   3643         int currentConfig = super.getLteOnCdmaMode();
   3644         int lteOnCdmaModeDynamicValue = currentConfig;
   3645 
   3646         UiccCardApplication cdmaApplication =
   3647                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
   3648         if (cdmaApplication != null && cdmaApplication.getType() == AppType.APPTYPE_RUIM) {
   3649             //Legacy RUIM cards don't support LTE.
   3650             lteOnCdmaModeDynamicValue = RILConstants.LTE_ON_CDMA_FALSE;
   3651 
   3652             //Override only if static configuration is TRUE.
   3653             if (currentConfig == RILConstants.LTE_ON_CDMA_TRUE) {
   3654                 return lteOnCdmaModeDynamicValue;
   3655             }
   3656         }
   3657         return currentConfig;
   3658     }
   3659 }
   3660