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