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