Home | History | Annotate | Download | only in cdma
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony.cdma;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.SharedPreferences;
     24 import android.database.SQLException;
     25 import android.net.Uri;
     26 import android.os.AsyncResult;
     27 import android.os.Handler;
     28 import android.os.Message;
     29 import android.os.PowerManager;
     30 import android.os.PowerManager.WakeLock;
     31 import android.os.Registrant;
     32 import android.os.RegistrantList;
     33 import android.os.SystemProperties;
     34 import android.os.UserHandle;
     35 import android.preference.PreferenceManager;
     36 import android.provider.Telephony;
     37 import android.telephony.CellLocation;
     38 import android.telephony.PhoneNumberUtils;
     39 import android.telephony.ServiceState;
     40 import android.telephony.SignalStrength;
     41 import android.text.TextUtils;
     42 import android.util.Log;
     43 
     44 import com.android.internal.telephony.Call;
     45 import com.android.internal.telephony.CallStateException;
     46 import com.android.internal.telephony.CallTracker;
     47 import com.android.internal.telephony.CommandException;
     48 import com.android.internal.telephony.CommandsInterface;
     49 import com.android.internal.telephony.Connection;
     50 import com.android.internal.telephony.IccCard;
     51 import com.android.internal.telephony.IccException;
     52 import com.android.internal.telephony.IccFileHandler;
     53 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
     54 import com.android.internal.telephony.IccRecords;
     55 import com.android.internal.telephony.IccSmsInterfaceManager;
     56 import com.android.internal.telephony.MccTable;
     57 import com.android.internal.telephony.MmiCode;
     58 import com.android.internal.telephony.OperatorInfo;
     59 import com.android.internal.telephony.Phone;
     60 import com.android.internal.telephony.PhoneBase;
     61 import com.android.internal.telephony.PhoneConstants;
     62 import com.android.internal.telephony.PhoneNotifier;
     63 import com.android.internal.telephony.PhoneProxy;
     64 import com.android.internal.telephony.PhoneSubInfo;
     65 import com.android.internal.telephony.ServiceStateTracker;
     66 import com.android.internal.telephony.TelephonyIntents;
     67 import com.android.internal.telephony.TelephonyProperties;
     68 import com.android.internal.telephony.UiccCard;
     69 import com.android.internal.telephony.UiccCardApplication;
     70 import com.android.internal.telephony.UUSInfo;
     71 import com.android.internal.telephony.IccCardApplicationStatus.AppState;
     72 import com.android.internal.telephony.cat.CatService;
     73 import com.android.internal.telephony.uicc.UiccController;
     74 
     75 import java.io.FileDescriptor;
     76 import java.io.PrintWriter;
     77 import java.util.ArrayList;
     78 import java.util.List;
     79 import java.util.regex.Matcher;
     80 import java.util.regex.Pattern;
     81 
     82 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
     83 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
     84 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
     85 
     86 /**
     87  * {@hide}
     88  */
     89 public class CDMAPhone extends PhoneBase {
     90     static final String LOG_TAG = "CDMA";
     91     private static final boolean DBG = true;
     92     private static final boolean VDBG = false; /* STOP SHIP if true */
     93 
     94     // Default Emergency Callback Mode exit timer
     95     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
     96 
     97     static final String VM_COUNT_CDMA = "vm_count_key_cdma";
     98     private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
     99     private String mVmNumber = null;
    100 
    101     static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
    102     static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
    103 
    104     // Instance Variables
    105     CdmaCallTracker mCT;
    106     CdmaServiceStateTracker mSST;
    107     CdmaSubscriptionSourceManager mCdmaSSM;
    108     ArrayList <CdmaMmiCode> mPendingMmis = new ArrayList<CdmaMmiCode>();
    109     RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
    110     RuimSmsInterfaceManager mRuimSmsInterfaceManager;
    111     int mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
    112     PhoneSubInfo mSubInfo;
    113     EriManager mEriManager;
    114     WakeLock mWakeLock;
    115 
    116     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
    117     private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
    118 
    119     // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
    120     private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
    121 
    122     // mEcmExitRespRegistrant is informed after the phone has been exited
    123     //the emergency callback mode
    124     //keep track of if phone is in emergency callback mode
    125     private boolean mIsPhoneInEcmState;
    126     private Registrant mEcmExitRespRegistrant;
    127     protected String mImei;
    128     protected String mImeiSv;
    129     private String mEsn;
    130     private String mMeid;
    131     // string to define how the carrier specifies its own ota sp number
    132     private String mCarrierOtaSpNumSchema;
    133 
    134     // A runnable which is used to automatically exit from Ecm after a period of time.
    135     private Runnable mExitEcmRunnable = new Runnable() {
    136         @Override
    137         public void run() {
    138             exitEmergencyCallbackMode();
    139         }
    140     };
    141 
    142     Registrant mPostDialHandler;
    143 
    144     static String PROPERTY_CDMA_HOME_OPERATOR_NUMERIC = "ro.cdma.home.operator.numeric";
    145 
    146     // Constructors
    147     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
    148         super(notifier, context, ci, false);
    149         initSstIcc();
    150         init(context, notifier);
    151     }
    152 
    153     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
    154             boolean unitTestMode) {
    155         super(notifier, context, ci, unitTestMode);
    156         initSstIcc();
    157         init(context, notifier);
    158     }
    159 
    160     protected void initSstIcc() {
    161         mSST = new CdmaServiceStateTracker(this);
    162     }
    163 
    164     protected void init(Context context, PhoneNotifier notifier) {
    165         mCM.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
    166         mCT = new CdmaCallTracker(this);
    167         mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context, mCM, this,
    168                 EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
    169         mSMS = new CdmaSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
    170         mDataConnectionTracker = new CdmaDataConnectionTracker (this);
    171         mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
    172         mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS);
    173         mSubInfo = new PhoneSubInfo(this);
    174         mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
    175 
    176         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
    177         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
    178         mCM.registerForOn(this, EVENT_RADIO_ON, null);
    179         mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
    180         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
    181         mCM.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
    182 
    183         PowerManager pm
    184             = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    185         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG);
    186 
    187         //Change the system setting
    188         SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
    189                 Integer.toString(PhoneConstants.PHONE_TYPE_CDMA));
    190 
    191         // This is needed to handle phone process crashes
    192         String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
    193         mIsPhoneInEcmState = inEcm.equals("true");
    194         if (mIsPhoneInEcmState) {
    195             // Send a message which will invoke handleExitEmergencyCallbackMode
    196             mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
    197         }
    198 
    199         // get the string that specifies the carrier OTA Sp number
    200         mCarrierOtaSpNumSchema = SystemProperties.get(
    201                 TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,"");
    202 
    203         // Sets operator alpha property by retrieving from build-time system property
    204         String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
    205         setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha);
    206 
    207         // Sets operator numeric property by retrieving from build-time system property
    208         String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
    209         log("CDMAPhone: init set 'gsm.sim.operator.numeric' to operator='" +
    210                 operatorNumeric + "'");
    211         setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric);
    212 
    213         // Sets iso country property by retrieving from build-time system property
    214         setIsoCountryProperty(operatorNumeric);
    215 
    216         // Sets current entry in the telephony carrier table
    217         updateCurrentCarrierInProvider(operatorNumeric);
    218 
    219         // Notify voicemails.
    220         notifier.notifyMessageWaitingChanged(this);
    221     }
    222 
    223     @Override
    224     public void dispose() {
    225         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
    226             super.dispose();
    227             log("dispose");
    228 
    229             //Unregister from all former registered events
    230             unregisterForRuimRecordEvents();
    231             mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
    232             mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
    233             mCM.unregisterForOn(this); //EVENT_RADIO_ON
    234             mSST.unregisterForNetworkAttached(this); //EVENT_REGISTERED_TO_NETWORK
    235             mCM.unSetOnSuppServiceNotification(this);
    236             removeCallbacks(mExitEcmRunnable);
    237 
    238             mPendingMmis.clear();
    239 
    240             //Force all referenced classes to unregister their former registered events
    241             mCT.dispose();
    242             mDataConnectionTracker.dispose();
    243             mSST.dispose();
    244             mCdmaSSM.dispose(this);
    245             mSMS.dispose();
    246             mRuimPhoneBookInterfaceManager.dispose();
    247             mRuimSmsInterfaceManager.dispose();
    248             mSubInfo.dispose();
    249             mEriManager.dispose();
    250         }
    251     }
    252 
    253     @Override
    254     public void removeReferences() {
    255         log("removeReferences");
    256         mRuimPhoneBookInterfaceManager = null;
    257         mRuimSmsInterfaceManager = null;
    258         mSubInfo = null;
    259         mCT = null;
    260         mSST = null;
    261         mEriManager = null;
    262         mExitEcmRunnable = null;
    263         super.removeReferences();
    264     }
    265 
    266     @Override
    267     protected void finalize() {
    268         if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized");
    269         if (mWakeLock.isHeld()) {
    270             Log.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
    271             mWakeLock.release();
    272         }
    273     }
    274 
    275     public ServiceState getServiceState() {
    276         return mSST.ss;
    277     }
    278 
    279     public CallTracker getCallTracker() {
    280         return mCT;
    281     }
    282 
    283     public PhoneConstants.State getState() {
    284         return mCT.state;
    285     }
    286 
    287     public ServiceStateTracker getServiceStateTracker() {
    288         return mSST;
    289     }
    290 
    291     public String getPhoneName() {
    292         return "CDMA";
    293     }
    294 
    295     public int getPhoneType() {
    296         return PhoneConstants.PHONE_TYPE_CDMA;
    297     }
    298 
    299     public boolean canTransfer() {
    300         Log.e(LOG_TAG, "canTransfer: not possible in CDMA");
    301         return false;
    302     }
    303 
    304     public CdmaCall getRingingCall() {
    305         return mCT.ringingCall;
    306     }
    307 
    308     public void setMute(boolean muted) {
    309         mCT.setMute(muted);
    310     }
    311 
    312     public boolean getMute() {
    313         return mCT.getMute();
    314     }
    315 
    316     public void conference() throws CallStateException {
    317         // three way calls in CDMA will be handled by feature codes
    318         Log.e(LOG_TAG, "conference: not possible in CDMA");
    319     }
    320 
    321     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
    322         this.mCM.setPreferredVoicePrivacy(enable, onComplete);
    323     }
    324 
    325     public void getEnhancedVoicePrivacy(Message onComplete) {
    326         this.mCM.getPreferredVoicePrivacy(onComplete);
    327     }
    328 
    329     public void clearDisconnected() {
    330         mCT.clearDisconnected();
    331     }
    332 
    333     public DataActivityState getDataActivityState() {
    334         DataActivityState ret = DataActivityState.NONE;
    335 
    336         if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
    337 
    338             switch (mDataConnectionTracker.getActivity()) {
    339                 case DATAIN:
    340                     ret = DataActivityState.DATAIN;
    341                 break;
    342 
    343                 case DATAOUT:
    344                     ret = DataActivityState.DATAOUT;
    345                 break;
    346 
    347                 case DATAINANDOUT:
    348                     ret = DataActivityState.DATAINANDOUT;
    349                 break;
    350 
    351                 case DORMANT:
    352                     ret = DataActivityState.DORMANT;
    353                 break;
    354             }
    355         }
    356         return ret;
    357     }
    358 
    359     public Connection
    360     dial (String dialString) throws CallStateException {
    361         // Need to make sure dialString gets parsed properly
    362         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
    363         return mCT.dial(newDialString);
    364     }
    365 
    366     public Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException {
    367         throw new CallStateException("Sending UUS information NOT supported in CDMA!");
    368     }
    369 
    370     public boolean
    371     getMessageWaitingIndicator() {
    372         return (getVoiceMessageCount() > 0);
    373     }
    374 
    375     public List<? extends MmiCode>
    376     getPendingMmiCodes() {
    377         return mPendingMmis;
    378     }
    379 
    380     public void registerForSuppServiceNotification(
    381             Handler h, int what, Object obj) {
    382         Log.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!");
    383     }
    384 
    385     public CdmaCall getBackgroundCall() {
    386         return mCT.backgroundCall;
    387     }
    388 
    389     public boolean handleInCallMmiCommands(String dialString) {
    390         Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!");
    391         return false;
    392     }
    393 
    394     boolean isInCall() {
    395         CdmaCall.State foregroundCallState = getForegroundCall().getState();
    396         CdmaCall.State backgroundCallState = getBackgroundCall().getState();
    397         CdmaCall.State ringingCallState = getRingingCall().getState();
    398 
    399         return (foregroundCallState.isAlive() || backgroundCallState.isAlive() || ringingCallState
    400                 .isAlive());
    401     }
    402 
    403     public void
    404     setNetworkSelectionModeAutomatic(Message response) {
    405         Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
    406     }
    407 
    408     public void unregisterForSuppServiceNotification(Handler h) {
    409         Log.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!");
    410     }
    411 
    412     public void
    413     acceptCall() throws CallStateException {
    414         mCT.acceptCall();
    415     }
    416 
    417     public void
    418     rejectCall() throws CallStateException {
    419         mCT.rejectCall();
    420     }
    421 
    422     public void
    423     switchHoldingAndActive() throws CallStateException {
    424         mCT.switchWaitingOrHoldingAndActive();
    425     }
    426 
    427     public String getLine1Number() {
    428         return mSST.getMdnNumber();
    429     }
    430 
    431     public String getCdmaPrlVersion(){
    432         return mSST.getPrlVersion();
    433     }
    434 
    435     public String getCdmaMin() {
    436         return mSST.getCdmaMin();
    437     }
    438 
    439     public boolean isMinInfoReady() {
    440         return mSST.isMinInfoReady();
    441     }
    442 
    443     public void getCallWaiting(Message onComplete) {
    444         mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
    445     }
    446 
    447     public void
    448     setRadioPower(boolean power) {
    449         mSST.setRadioPower(power);
    450     }
    451 
    452     public String getEsn() {
    453         return mEsn;
    454     }
    455 
    456     public String getMeid() {
    457         return mMeid;
    458     }
    459 
    460     //returns MEID or ESN in CDMA
    461     public String getDeviceId() {
    462         String id = getMeid();
    463         if ((id == null) || id.matches("^0*$")) {
    464             Log.d(LOG_TAG, "getDeviceId(): MEID is not initialized use ESN");
    465             id = getEsn();
    466         }
    467         return id;
    468     }
    469 
    470     public String getDeviceSvn() {
    471         Log.d(LOG_TAG, "getDeviceSvn(): return 0");
    472         return "0";
    473     }
    474 
    475     public String getSubscriberId() {
    476         return mSST.getImsi();
    477     }
    478 
    479     public String getImei() {
    480         Log.e(LOG_TAG, "IMEI is not available in CDMA");
    481         return null;
    482     }
    483 
    484     public boolean canConference() {
    485         Log.e(LOG_TAG, "canConference: not possible in CDMA");
    486         return false;
    487     }
    488 
    489     public CellLocation getCellLocation() {
    490         return mSST.cellLoc;
    491     }
    492 
    493     public CdmaCall getForegroundCall() {
    494         return mCT.foregroundCall;
    495     }
    496 
    497     public void
    498     selectNetworkManually(OperatorInfo network,
    499             Message response) {
    500         Log.e(LOG_TAG, "selectNetworkManually: not possible in CDMA");
    501     }
    502 
    503     public void setOnPostDialCharacter(Handler h, int what, Object obj) {
    504         mPostDialHandler = new Registrant(h, what, obj);
    505     }
    506 
    507     public boolean handlePinMmi(String dialString) {
    508         CdmaMmiCode mmi = CdmaMmiCode.newFromDialString(dialString, this);
    509 
    510         if (mmi == null) {
    511             Log.e(LOG_TAG, "Mmi is NULL!");
    512             return false;
    513         } else if (mmi.isPukCommand()) {
    514             mPendingMmis.add(mmi);
    515             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
    516             mmi.processCode();
    517             return true;
    518         }
    519         Log.e(LOG_TAG, "Unrecognized mmi!");
    520         return false;
    521     }
    522 
    523     /**
    524      * Removes the given MMI from the pending list and notifies registrants that
    525      * it is complete.
    526      *
    527      * @param mmi MMI that is done
    528      */
    529     void onMMIDone(CdmaMmiCode mmi) {
    530         /*
    531          * Only notify complete if it's on the pending list. Otherwise, it's
    532          * already been handled (eg, previously canceled).
    533          */
    534         if (mPendingMmis.remove(mmi)) {
    535             mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
    536         }
    537     }
    538 
    539     public void setLine1Number(String alphaTag, String number, Message onComplete) {
    540         Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
    541     }
    542 
    543     public void setCallWaiting(boolean enable, Message onComplete) {
    544         Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!");
    545     }
    546 
    547     public void updateServiceLocation() {
    548         mSST.enableSingleLocationUpdate();
    549     }
    550 
    551     public void setDataRoamingEnabled(boolean enable) {
    552         mDataConnectionTracker.setDataOnRoamingEnabled(enable);
    553     }
    554 
    555     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
    556         mCM.registerForCdmaOtaProvision(h, what, obj);
    557     }
    558 
    559     public void unregisterForCdmaOtaStatusChange(Handler h) {
    560         mCM.unregisterForCdmaOtaProvision(h);
    561     }
    562 
    563     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
    564         mSST.registerForSubscriptionInfoReady(h, what, obj);
    565     }
    566 
    567     public void unregisterForSubscriptionInfoReady(Handler h) {
    568         mSST.unregisterForSubscriptionInfoReady(h);
    569     }
    570 
    571     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
    572         mEcmExitRespRegistrant = new Registrant (h, what, obj);
    573     }
    574 
    575     public void unsetOnEcbModeExitResponse(Handler h) {
    576         mEcmExitRespRegistrant.clear();
    577     }
    578 
    579     public void registerForCallWaiting(Handler h, int what, Object obj) {
    580         mCT.registerForCallWaiting(h, what, obj);
    581     }
    582 
    583     public void unregisterForCallWaiting(Handler h) {
    584         mCT.unregisterForCallWaiting(h);
    585     }
    586 
    587     public void
    588     getNeighboringCids(Message response) {
    589         /*
    590          * This is currently not implemented.  At least as of June
    591          * 2009, there is no neighbor cell information available for
    592          * CDMA because some party is resisting making this
    593          * information readily available.  Consequently, calling this
    594          * function can have no useful effect.  This situation may
    595          * (and hopefully will) change in the future.
    596          */
    597         if (response != null) {
    598             CommandException ce = new CommandException(
    599                     CommandException.Error.REQUEST_NOT_SUPPORTED);
    600             AsyncResult.forMessage(response).exception = ce;
    601             response.sendToTarget();
    602         }
    603     }
    604 
    605     public PhoneConstants.DataState getDataConnectionState(String apnType) {
    606         PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
    607 
    608         if (mSST == null) {
    609              // Radio Technology Change is ongoning, dispose() and removeReferences() have
    610              // already been called
    611 
    612              ret = PhoneConstants.DataState.DISCONNECTED;
    613         } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
    614             // If we're out of service, open TCP sockets may still work
    615             // but no data will flow
    616             ret = PhoneConstants.DataState.DISCONNECTED;
    617         } else if (mDataConnectionTracker.isApnTypeEnabled(apnType) == false ||
    618                 mDataConnectionTracker.isApnTypeActive(apnType) == false) {
    619             ret = PhoneConstants.DataState.DISCONNECTED;
    620         } else {
    621             switch (mDataConnectionTracker.getState(apnType)) {
    622                 case FAILED:
    623                 case IDLE:
    624                     ret = PhoneConstants.DataState.DISCONNECTED;
    625                 break;
    626 
    627                 case CONNECTED:
    628                 case DISCONNECTING:
    629                     if ( mCT.state != PhoneConstants.State.IDLE
    630                             && !mSST.isConcurrentVoiceAndDataAllowed()) {
    631                         ret = PhoneConstants.DataState.SUSPENDED;
    632                     } else {
    633                         ret = PhoneConstants.DataState.CONNECTED;
    634                     }
    635                 break;
    636 
    637                 case INITING:
    638                 case CONNECTING:
    639                 case SCANNING:
    640                     ret = PhoneConstants.DataState.CONNECTING;
    641                 break;
    642             }
    643         }
    644 
    645         log("getDataConnectionState apnType=" + apnType + " ret=" + ret);
    646         return ret;
    647     }
    648 
    649     public void sendUssdResponse(String ussdMessge) {
    650         Log.e(LOG_TAG, "sendUssdResponse: not possible in CDMA");
    651     }
    652 
    653     public void sendDtmf(char c) {
    654         if (!PhoneNumberUtils.is12Key(c)) {
    655             Log.e(LOG_TAG,
    656                     "sendDtmf called with invalid character '" + c + "'");
    657         } else {
    658             if (mCT.state ==  PhoneConstants.State.OFFHOOK) {
    659                 mCM.sendDtmf(c, null);
    660             }
    661         }
    662     }
    663 
    664     public void startDtmf(char c) {
    665         if (!PhoneNumberUtils.is12Key(c)) {
    666             Log.e(LOG_TAG,
    667                     "startDtmf called with invalid character '" + c + "'");
    668         } else {
    669             mCM.startDtmf(c, null);
    670         }
    671     }
    672 
    673     public void stopDtmf() {
    674         mCM.stopDtmf(null);
    675     }
    676 
    677     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
    678         boolean check = true;
    679         for (int itr = 0;itr < dtmfString.length(); itr++) {
    680             if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
    681                 Log.e(LOG_TAG,
    682                         "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
    683                 check = false;
    684                 break;
    685             }
    686         }
    687         if ((mCT.state ==  PhoneConstants.State.OFFHOOK)&&(check)) {
    688             mCM.sendBurstDtmf(dtmfString, on, off, onComplete);
    689         }
    690      }
    691 
    692     public void getAvailableNetworks(Message response) {
    693         Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
    694     }
    695 
    696     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
    697         Log.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA");
    698     }
    699 
    700     public void enableLocationUpdates() {
    701         mSST.enableLocationUpdates();
    702     }
    703 
    704     public void disableLocationUpdates() {
    705         mSST.disableLocationUpdates();
    706     }
    707 
    708     public void getDataCallList(Message response) {
    709         mCM.getDataCallList(response);
    710     }
    711 
    712     public boolean getDataRoamingEnabled() {
    713         return mDataConnectionTracker.getDataOnRoamingEnabled();
    714     }
    715 
    716     public void setVoiceMailNumber(String alphaTag,
    717                                    String voiceMailNumber,
    718                                    Message onComplete) {
    719         Message resp;
    720         mVmNumber = voiceMailNumber;
    721         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
    722         IccRecords r = mIccRecords.get();
    723         if (r != null) {
    724             r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
    725         }
    726     }
    727 
    728     public String getVoiceMailNumber() {
    729         String number = null;
    730         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
    731         // TODO: The default value of voicemail number should be read from a system property
    732 
    733         // Read platform settings for dynamic voicemail number
    734         if (getContext().getResources().getBoolean(com.android.internal
    735                 .R.bool.config_telephony_use_own_number_for_voicemail)) {
    736             number = sp.getString(VM_NUMBER_CDMA, getLine1Number());
    737         } else {
    738             number = sp.getString(VM_NUMBER_CDMA, "*86");
    739         }
    740         return number;
    741     }
    742 
    743     /* Returns Number of Voicemails
    744      * @hide
    745      */
    746     public int getVoiceMessageCount() {
    747         IccRecords r = mIccRecords.get();
    748         int voicemailCount =  (r != null) ? r.getVoiceMessageCount() : 0;
    749         // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility
    750         // that phone was power cycled and would have lost the voicemail count.
    751         // So get the count from preferences.
    752         if (voicemailCount == 0) {
    753             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
    754             voicemailCount = sp.getInt(VM_COUNT_CDMA, 0);
    755         }
    756         return voicemailCount;
    757     }
    758 
    759     public String getVoiceMailAlphaTag() {
    760         // TODO: Where can we get this value has to be clarified with QC.
    761         String ret = "";//TODO: Remove = "", if we know where to get this value.
    762 
    763         //ret = mSIMRecords.getVoiceMailAlphaTag();
    764 
    765         if (ret == null || ret.length() == 0) {
    766             return mContext.getText(
    767                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
    768         }
    769 
    770         return ret;
    771     }
    772 
    773     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
    774         Log.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA");
    775     }
    776 
    777     public void setCallForwardingOption(int commandInterfaceCFAction,
    778             int commandInterfaceCFReason,
    779             String dialingNumber,
    780             int timerSeconds,
    781             Message onComplete) {
    782         Log.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA");
    783     }
    784 
    785     public void
    786     getOutgoingCallerIdDisplay(Message onComplete) {
    787         Log.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA");
    788     }
    789 
    790     public boolean
    791     getCallForwardingIndicator() {
    792         Log.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA");
    793         return false;
    794     }
    795 
    796     public void explicitCallTransfer() {
    797         Log.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA");
    798     }
    799 
    800     public String getLine1AlphaTag() {
    801         Log.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA");
    802         return null;
    803     }
    804 
    805     /**
    806      * Notify any interested party of a Phone state change  {@link PhoneConstants.State}
    807      */
    808     /*package*/ void notifyPhoneStateChanged() {
    809         mNotifier.notifyPhoneState(this);
    810     }
    811 
    812     /**
    813      * Notify registrants of a change in the call state. This notifies changes in {@link Call.State}
    814      * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged.
    815      */
    816     /*package*/ void notifyPreciseCallStateChanged() {
    817         /* we'd love it if this was package-scoped*/
    818         super.notifyPreciseCallStateChangedP();
    819     }
    820 
    821      void notifyServiceStateChanged(ServiceState ss) {
    822          super.notifyServiceStateChangedP(ss);
    823      }
    824 
    825      void notifyLocationChanged() {
    826          mNotifier.notifyCellLocation(this);
    827      }
    828 
    829     /*package*/ void notifyNewRingingConnection(Connection c) {
    830         /* we'd love it if this was package-scoped*/
    831         super.notifyNewRingingConnectionP(c);
    832     }
    833 
    834     /*package*/ void notifyDisconnect(Connection cn) {
    835         mDisconnectRegistrants.notifyResult(cn);
    836     }
    837 
    838     void notifyUnknownConnection() {
    839         mUnknownConnectionRegistrants.notifyResult(this);
    840     }
    841 
    842     public boolean isInEmergencyCall() {
    843         return mCT.isInEmergencyCall();
    844     }
    845 
    846     public boolean isInEcm() {
    847         return mIsPhoneInEcmState;
    848     }
    849 
    850     void sendEmergencyCallbackModeChange(){
    851         //Send an Intent
    852         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
    853         intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
    854         ActivityManagerNative.broadcastStickyIntent(intent,null,UserHandle.USER_ALL);
    855         if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange");
    856     }
    857 
    858     @Override
    859     public void exitEmergencyCallbackMode() {
    860         if (mWakeLock.isHeld()) {
    861             mWakeLock.release();
    862         }
    863         // Send a message which will invoke handleExitEmergencyCallbackMode
    864         mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
    865     }
    866 
    867     private void handleEnterEmergencyCallbackMode(Message msg) {
    868         if (DBG) {
    869             Log.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
    870                     + mIsPhoneInEcmState);
    871         }
    872         // if phone is not in Ecm mode, and it's changed to Ecm mode
    873         if (mIsPhoneInEcmState == false) {
    874             mIsPhoneInEcmState = true;
    875             // notify change
    876             sendEmergencyCallbackModeChange();
    877             setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
    878 
    879             // Post this runnable so we will automatically exit
    880             // if no one invokes exitEmergencyCallbackMode() directly.
    881             long delayInMillis = SystemProperties.getLong(
    882                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
    883             postDelayed(mExitEcmRunnable, delayInMillis);
    884             // We don't want to go to sleep while in Ecm
    885             mWakeLock.acquire();
    886         }
    887     }
    888 
    889     private void handleExitEmergencyCallbackMode(Message msg) {
    890         AsyncResult ar = (AsyncResult)msg.obj;
    891         if (DBG) {
    892             Log.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
    893                     + ar.exception + mIsPhoneInEcmState);
    894         }
    895         // Remove pending exit Ecm runnable, if any
    896         removeCallbacks(mExitEcmRunnable);
    897 
    898         if (mEcmExitRespRegistrant != null) {
    899             mEcmExitRespRegistrant.notifyRegistrant(ar);
    900         }
    901         // if exiting ecm success
    902         if (ar.exception == null) {
    903             if (mIsPhoneInEcmState) {
    904                 mIsPhoneInEcmState = false;
    905                 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
    906             }
    907             // send an Intent
    908             sendEmergencyCallbackModeChange();
    909             // Re-initiate data connection
    910             mDataConnectionTracker.setInternalDataEnabled(true);
    911         }
    912     }
    913 
    914     /**
    915      * Handle to cancel or restart Ecm timer in emergency call back mode
    916      * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
    917      * otherwise, restart Ecm timer and notify apps the timer is restarted.
    918      */
    919     void handleTimerInEmergencyCallbackMode(int action) {
    920         switch(action) {
    921         case CANCEL_ECM_TIMER:
    922             removeCallbacks(mExitEcmRunnable);
    923             mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE);
    924             break;
    925         case RESTART_ECM_TIMER:
    926             long delayInMillis = SystemProperties.getLong(
    927                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
    928             postDelayed(mExitEcmRunnable, delayInMillis);
    929             mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE);
    930             break;
    931         default:
    932             Log.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
    933         }
    934     }
    935 
    936     /**
    937      * Registration point for Ecm timer reset
    938      * @param h handler to notify
    939      * @param what User-defined message code
    940      * @param obj placed in Message.obj
    941      */
    942     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
    943         mEcmTimerResetRegistrants.addUnique(h, what, obj);
    944     }
    945 
    946     public void unregisterForEcmTimerReset(Handler h) {
    947         mEcmTimerResetRegistrants.remove(h);
    948     }
    949 
    950     @Override
    951     public void handleMessage(Message msg) {
    952         AsyncResult ar;
    953         Message     onComplete;
    954 
    955         switch(msg.what) {
    956             case EVENT_RADIO_AVAILABLE: {
    957                 mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
    958 
    959                 mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
    960             }
    961             break;
    962 
    963             case EVENT_GET_BASEBAND_VERSION_DONE:{
    964                 ar = (AsyncResult)msg.obj;
    965 
    966                 if (ar.exception != null) {
    967                     break;
    968                 }
    969 
    970                 if (DBG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
    971                 setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result);
    972             }
    973             break;
    974 
    975             case EVENT_GET_DEVICE_IDENTITY_DONE:{
    976                 ar = (AsyncResult)msg.obj;
    977 
    978                 if (ar.exception != null) {
    979                     break;
    980                 }
    981                 String[] respId = (String[])ar.result;
    982                 mImei = respId[0];
    983                 mImeiSv = respId[1];
    984                 mEsn  =  respId[2];
    985                 mMeid =  respId[3];
    986             }
    987             break;
    988 
    989             case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
    990                 handleEnterEmergencyCallbackMode(msg);
    991             }
    992             break;
    993 
    994             case EVENT_ICC_RECORD_EVENTS:
    995                 ar = (AsyncResult)msg.obj;
    996                 processIccRecordEvents((Integer)ar.result);
    997                 break;
    998 
    999             case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
   1000                 handleExitEmergencyCallbackMode(msg);
   1001             }
   1002             break;
   1003 
   1004             case EVENT_RUIM_RECORDS_LOADED:{
   1005                 Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
   1006                 updateCurrentCarrierInProvider();
   1007             }
   1008             break;
   1009 
   1010             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{
   1011                 Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
   1012             }
   1013             break;
   1014 
   1015             case EVENT_RADIO_ON:{
   1016                 Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received");
   1017                 handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource());
   1018             }
   1019             break;
   1020 
   1021             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:{
   1022                 Log.d(LOG_TAG, "EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED");
   1023                 handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource());
   1024             }
   1025             break;
   1026 
   1027             case EVENT_SSN:{
   1028                 Log.d(LOG_TAG, "Event EVENT_SSN Received");
   1029             }
   1030             break;
   1031 
   1032             case EVENT_REGISTERED_TO_NETWORK:{
   1033                 Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received");
   1034             }
   1035             break;
   1036 
   1037             case EVENT_NV_READY:{
   1038                 Log.d(LOG_TAG, "Event EVENT_NV_READY Received");
   1039                 prepareEri();
   1040             }
   1041             break;
   1042 
   1043             case EVENT_SET_VM_NUMBER_DONE:{
   1044                 ar = (AsyncResult)msg.obj;
   1045                 if (IccException.class.isInstance(ar.exception)) {
   1046                     storeVoiceMailNumber(mVmNumber);
   1047                     ar.exception = null;
   1048                 }
   1049                 onComplete = (Message) ar.userObj;
   1050                 if (onComplete != null) {
   1051                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
   1052                     onComplete.sendToTarget();
   1053                 }
   1054             }
   1055             break;
   1056 
   1057             default:{
   1058                 super.handleMessage(msg);
   1059             }
   1060         }
   1061     }
   1062 
   1063     @Override
   1064     protected void onUpdateIccAvailability() {
   1065         if (mUiccController == null ) {
   1066             return;
   1067         }
   1068 
   1069         UiccCardApplication newUiccApplication =
   1070                 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP2);
   1071 
   1072         UiccCardApplication app = mUiccApplication.get();
   1073         if (app != newUiccApplication) {
   1074             if (app != null) {
   1075                 log("Removing stale icc objects.");
   1076                 if (mIccRecords.get() != null) {
   1077                     unregisterForRuimRecordEvents();
   1078                     mRuimPhoneBookInterfaceManager.updateIccRecords(null);
   1079                 }
   1080                 mIccRecords.set(null);
   1081                 mUiccApplication.set(null);
   1082             }
   1083             if (newUiccApplication != null) {
   1084                 log("New Uicc application found");
   1085                 mUiccApplication.set(newUiccApplication);
   1086                 mIccRecords.set(newUiccApplication.getIccRecords());
   1087                 registerForRuimRecordEvents();
   1088                 mRuimPhoneBookInterfaceManager.updateIccRecords(mIccRecords.get());
   1089             }
   1090         }
   1091     }
   1092 
   1093     private void processIccRecordEvents(int eventCode) {
   1094         switch (eventCode) {
   1095             case RuimRecords.EVENT_MWI:
   1096                 notifyMessageWaitingIndicator();
   1097                 break;
   1098 
   1099             default:
   1100                 Log.e(LOG_TAG,"Unknown icc records event code " + eventCode);
   1101                 break;
   1102         }
   1103     }
   1104 
   1105     /**
   1106      * Handles the call to get the subscription source
   1107      *
   1108      * @param newSubscriptionSource holds the new CDMA subscription source value
   1109      */
   1110     private void handleCdmaSubscriptionSource(int newSubscriptionSource) {
   1111         if (newSubscriptionSource != mCdmaSubscriptionSource) {
   1112              mCdmaSubscriptionSource = newSubscriptionSource;
   1113              if (newSubscriptionSource == CDMA_SUBSCRIPTION_NV) {
   1114                  // NV is ready when subscription source is NV
   1115                  sendMessage(obtainMessage(EVENT_NV_READY));
   1116              }
   1117         }
   1118     }
   1119 
   1120     /**
   1121      * Retrieves the PhoneSubInfo of the CDMAPhone
   1122      */
   1123     public PhoneSubInfo getPhoneSubInfo() {
   1124         return mSubInfo;
   1125     }
   1126 
   1127     /**
   1128      * Retrieves the IccSmsInterfaceManager of the CDMAPhone
   1129      */
   1130     public IccSmsInterfaceManager getIccSmsInterfaceManager() {
   1131         return mRuimSmsInterfaceManager;
   1132     }
   1133 
   1134     /**
   1135      * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone
   1136      */
   1137     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager() {
   1138         return mRuimPhoneBookInterfaceManager;
   1139     }
   1140 
   1141     public void registerForEriFileLoaded(Handler h, int what, Object obj) {
   1142         Registrant r = new Registrant (h, what, obj);
   1143         mEriFileLoadedRegistrants.add(r);
   1144     }
   1145 
   1146     public void unregisterForEriFileLoaded(Handler h) {
   1147         mEriFileLoadedRegistrants.remove(h);
   1148     }
   1149 
   1150     // override for allowing access from other classes of this package
   1151     /**
   1152      * {@inheritDoc}
   1153      */
   1154     public final void setSystemProperty(String property, String value) {
   1155         super.setSystemProperty(property, value);
   1156     }
   1157 
   1158     /**
   1159      * Activate or deactivate cell broadcast SMS.
   1160      *
   1161      * @param activate 0 = activate, 1 = deactivate
   1162      * @param response Callback message is empty on completion
   1163      */
   1164     public void activateCellBroadcastSms(int activate, Message response) {
   1165         Log.e(LOG_TAG, "[CDMAPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
   1166         response.sendToTarget();
   1167     }
   1168 
   1169     /**
   1170      * Query the current configuration of cdma cell broadcast SMS.
   1171      *
   1172      * @param response Callback message is empty on completion
   1173      */
   1174     public void getCellBroadcastSmsConfig(Message response) {
   1175         Log.e(LOG_TAG, "[CDMAPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
   1176         response.sendToTarget();
   1177     }
   1178 
   1179     /**
   1180      * Configure cdma cell broadcast SMS.
   1181      *
   1182      * @param response Callback message is empty on completion
   1183      */
   1184     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
   1185         Log.e(LOG_TAG, "[CDMAPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
   1186         response.sendToTarget();
   1187     }
   1188 
   1189     /**
   1190      * Returns true if OTA Service Provisioning needs to be performed.
   1191      */
   1192     @Override
   1193     public boolean needsOtaServiceProvisioning() {
   1194         return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
   1195     }
   1196 
   1197     private static final String IS683A_FEATURE_CODE = "*228";
   1198     private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
   1199     private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
   1200     private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
   1201 
   1202     private static final int IS683_CONST_800MHZ_A_BAND = 0;
   1203     private static final int IS683_CONST_800MHZ_B_BAND = 1;
   1204     private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
   1205     private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
   1206     private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
   1207     private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
   1208     private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
   1209     private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
   1210     private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
   1211 
   1212     private static boolean isIs683OtaSpDialStr(String dialStr) {
   1213         int sysSelCodeInt;
   1214         boolean isOtaspDialString = false;
   1215         int dialStrLen = dialStr.length();
   1216 
   1217         if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
   1218             if (dialStr.equals(IS683A_FEATURE_CODE)) {
   1219                 isOtaspDialString = true;
   1220             }
   1221         } else {
   1222             sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
   1223             switch (sysSelCodeInt) {
   1224                 case IS683_CONST_800MHZ_A_BAND:
   1225                 case IS683_CONST_800MHZ_B_BAND:
   1226                 case IS683_CONST_1900MHZ_A_BLOCK:
   1227                 case IS683_CONST_1900MHZ_B_BLOCK:
   1228                 case IS683_CONST_1900MHZ_C_BLOCK:
   1229                 case IS683_CONST_1900MHZ_D_BLOCK:
   1230                 case IS683_CONST_1900MHZ_E_BLOCK:
   1231                 case IS683_CONST_1900MHZ_F_BLOCK:
   1232                     isOtaspDialString = true;
   1233                     break;
   1234                 default:
   1235                     break;
   1236             }
   1237         }
   1238         return isOtaspDialString;
   1239     }
   1240     /**
   1241      * This function extracts the system selection code from the dial string.
   1242      */
   1243     private static int extractSelCodeFromOtaSpNum(String dialStr) {
   1244         int dialStrLen = dialStr.length();
   1245         int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
   1246 
   1247         if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
   1248                                    0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
   1249             (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
   1250                             IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
   1251                 // Since we checked the condition above, the system selection code
   1252                 // extracted from dialStr will not cause any exception
   1253                 sysSelCodeInt = Integer.parseInt (
   1254                                 dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
   1255                                 IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
   1256         }
   1257         if (DBG) Log.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
   1258         return sysSelCodeInt;
   1259     }
   1260 
   1261     /**
   1262      * This function checks if the system selection code extracted from
   1263      * the dial string "sysSelCodeInt' is the system selection code specified
   1264      * in the carrier ota sp number schema "sch".
   1265      */
   1266     private static boolean
   1267     checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) {
   1268         boolean isOtaSpNum = false;
   1269         try {
   1270             // Get how many number of system selection code ranges
   1271             int selRc = Integer.parseInt((String)sch[1]);
   1272             for (int i = 0; i < selRc; i++) {
   1273                 if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
   1274                     int selMin = Integer.parseInt((String)sch[i+2]);
   1275                     int selMax = Integer.parseInt((String)sch[i+3]);
   1276                     // Check if the selection code extracted from the dial string falls
   1277                     // within any of the range pairs specified in the schema.
   1278                     if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
   1279                         isOtaSpNum = true;
   1280                         break;
   1281                     }
   1282                 }
   1283             }
   1284         } catch (NumberFormatException ex) {
   1285             // If the carrier ota sp number schema is not correct, we still allow dial
   1286             // and only log the error:
   1287             Log.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
   1288         }
   1289         return isOtaSpNum;
   1290     }
   1291 
   1292     // Define the pattern/format for carrier specified OTASP number schema.
   1293     // It separates by comma and/or whitespace.
   1294     private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
   1295 
   1296     /**
   1297      * The following function checks if a dial string is a carrier specified
   1298      * OTASP number or not by checking against the OTASP number schema stored
   1299      * in PROPERTY_OTASP_NUM_SCHEMA.
   1300      *
   1301      * Currently, there are 2 schemas for carriers to specify the OTASP number:
   1302      * 1) Use system selection code:
   1303      *    The schema is:
   1304      *    SELC,the # of code pairs,min1,max1,min2,max2,...
   1305      *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
   1306      *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
   1307      *
   1308      * 2) Use feature code:
   1309      *    The schema is:
   1310      *    "FC,length of feature code,feature code".
   1311      *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
   1312      *     and the code itself is "*2".
   1313      */
   1314     private boolean isCarrierOtaSpNum(String dialStr) {
   1315         boolean isOtaSpNum = false;
   1316         int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
   1317         if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
   1318             return isOtaSpNum;
   1319         }
   1320         // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
   1321         if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
   1322             Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
   1323             if (DBG) {
   1324                 Log.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
   1325             }
   1326 
   1327             if (m.find()) {
   1328                 String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
   1329                 // If carrier uses system selection code mechanism
   1330                 if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
   1331                     if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
   1332                         isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
   1333                     } else {
   1334                         if (DBG) {
   1335                             Log.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
   1336                         }
   1337                     }
   1338                 } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
   1339                     int fcLen =  Integer.parseInt((String)sch[1]);
   1340                     String fc = (String)sch[2];
   1341                     if (dialStr.regionMatches(0,fc,0,fcLen)) {
   1342                         isOtaSpNum = true;
   1343                     } else {
   1344                         if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
   1345                     }
   1346                 } else {
   1347                     if (DBG) {
   1348                         Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
   1349                     }
   1350                 }
   1351             } else {
   1352                 if (DBG) {
   1353                     Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
   1354                           mCarrierOtaSpNumSchema);
   1355                 }
   1356             }
   1357         } else {
   1358             if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
   1359         }
   1360         return isOtaSpNum;
   1361     }
   1362 
   1363     /**
   1364      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
   1365      * OTASP dial string.
   1366      *
   1367      * @param dialStr the number to look up.
   1368      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
   1369      */
   1370     @Override
   1371     public  boolean isOtaSpNumber(String dialStr){
   1372         boolean isOtaSpNum = false;
   1373         String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr);
   1374         if (dialableStr != null) {
   1375             isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
   1376             if (isOtaSpNum == false) {
   1377                 isOtaSpNum = isCarrierOtaSpNum(dialableStr);
   1378             }
   1379         }
   1380         if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
   1381         return isOtaSpNum;
   1382     }
   1383 
   1384     @Override
   1385     public int getCdmaEriIconIndex() {
   1386         return getServiceState().getCdmaEriIconIndex();
   1387     }
   1388 
   1389     /**
   1390      * Returns the CDMA ERI icon mode,
   1391      * 0 - ON
   1392      * 1 - FLASHING
   1393      */
   1394     @Override
   1395     public int getCdmaEriIconMode() {
   1396         return getServiceState().getCdmaEriIconMode();
   1397     }
   1398 
   1399     /**
   1400      * Returns the CDMA ERI text,
   1401      */
   1402     @Override
   1403     public String getCdmaEriText() {
   1404         int roamInd = getServiceState().getCdmaRoamingIndicator();
   1405         int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
   1406         return mEriManager.getCdmaEriText(roamInd, defRoamInd);
   1407     }
   1408 
   1409     /**
   1410      * Store the voicemail number in preferences
   1411      */
   1412     private void storeVoiceMailNumber(String number) {
   1413         // Update the preference value of voicemail number
   1414         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   1415         SharedPreferences.Editor editor = sp.edit();
   1416         editor.putString(VM_NUMBER_CDMA, number);
   1417         editor.apply();
   1418     }
   1419 
   1420     /**
   1421      * Sets PROPERTY_ICC_OPERATOR_ISO_COUNTRY property
   1422      *
   1423      */
   1424     private void setIsoCountryProperty(String operatorNumeric) {
   1425         if (TextUtils.isEmpty(operatorNumeric)) {
   1426             setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
   1427         } else {
   1428             String iso = "";
   1429             try {
   1430                 iso = MccTable.countryCodeForMcc(Integer.parseInt(
   1431                         operatorNumeric.substring(0,3)));
   1432             } catch (NumberFormatException ex) {
   1433                 Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
   1434             } catch (StringIndexOutOfBoundsException ex) {
   1435                 Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
   1436             }
   1437 
   1438             setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, iso);
   1439         }
   1440     }
   1441 
   1442     /**
   1443      * Sets the "current" field in the telephony provider according to the
   1444      * build-time operator numeric property
   1445      *
   1446      * @return true for success; false otherwise.
   1447      */
   1448     boolean updateCurrentCarrierInProvider(String operatorNumeric) {
   1449         if (!TextUtils.isEmpty(operatorNumeric)) {
   1450             try {
   1451                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
   1452                 ContentValues map = new ContentValues();
   1453                 map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
   1454                 log("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric);
   1455                 getContext().getContentResolver().insert(uri, map);
   1456 
   1457                 // Updates MCC MNC device configuration information
   1458                 MccTable.updateMccMncConfiguration(mContext, operatorNumeric);
   1459 
   1460                 return true;
   1461             } catch (SQLException e) {
   1462                 Log.e(LOG_TAG, "Can't store current operator", e);
   1463             }
   1464         }
   1465         return false;
   1466     }
   1467 
   1468     /**
   1469      * Sets the "current" field in the telephony provider according to the SIM's operator.
   1470      * Implemented in {@link CDMALTEPhone} for CDMA/LTE devices.
   1471      *
   1472      * @return true for success; false otherwise.
   1473      */
   1474     boolean updateCurrentCarrierInProvider() {
   1475         return true;
   1476     }
   1477 
   1478     public void prepareEri() {
   1479         mEriManager.loadEriFile();
   1480         if(mEriManager.isEriFileLoaded()) {
   1481             // when the ERI file is loaded
   1482             log("ERI read, notify registrants");
   1483             mEriFileLoadedRegistrants.notifyRegistrants();
   1484         }
   1485     }
   1486 
   1487     public boolean isEriFileLoaded() {
   1488         return mEriManager.isEriFileLoaded();
   1489     }
   1490 
   1491     protected void registerForRuimRecordEvents() {
   1492         IccRecords r = mIccRecords.get();
   1493         if (r == null) {
   1494             return;
   1495         }
   1496         r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
   1497         r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
   1498     }
   1499 
   1500     protected void unregisterForRuimRecordEvents() {
   1501         IccRecords r = mIccRecords.get();
   1502         if (r == null) {
   1503             return;
   1504         }
   1505         r.unregisterForRecordsEvents(this);
   1506         r.unregisterForRecordsLoaded(this);
   1507     }
   1508 
   1509     protected void log(String s) {
   1510         if (DBG)
   1511             Log.d(LOG_TAG, "[CDMAPhone] " + s);
   1512     }
   1513 
   1514     @Override
   1515     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1516         pw.println("CDMAPhone extends:");
   1517         super.dump(fd, pw, args);
   1518         pw.println(" mVmNumber=" + mVmNumber);
   1519         pw.println(" mCT=" + mCT);
   1520         pw.println(" mSST=" + mSST);
   1521         pw.println(" mCdmaSSM=" + mCdmaSSM);
   1522         pw.println(" mPendingMmis=" + mPendingMmis);
   1523         pw.println(" mRuimPhoneBookInterfaceManager=" + mRuimPhoneBookInterfaceManager);
   1524         pw.println(" mRuimSmsInterfaceManager=" + mRuimSmsInterfaceManager);
   1525         pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource);
   1526         pw.println(" mSubInfo=" + mSubInfo);
   1527         pw.println(" mEriManager=" + mEriManager);
   1528         pw.println(" mWakeLock=" + mWakeLock);
   1529         pw.println(" mIsPhoneInEcmState=" + mIsPhoneInEcmState);
   1530         if (VDBG) pw.println(" mImei=" + mImei);
   1531         if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
   1532         if (VDBG) pw.println(" mEsn=" + mEsn);
   1533         if (VDBG) pw.println(" mMeid=" + mMeid);
   1534         pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema);
   1535         pw.println(" getCdmaEriIconIndex()=" + getCdmaEriIconIndex());
   1536         pw.println(" getCdmaEriIconMode()=" + getCdmaEriIconMode());
   1537         pw.println(" getCdmaEriText()=" + getCdmaEriText());
   1538         pw.println(" isMinInfoReady()=" + isMinInfoReady());
   1539         pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
   1540     }
   1541 }
   1542