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