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