Home | History | Annotate | Download | only in cdma
      1 /*
      2  * Copyright (C) 2012 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.AlarmManager;
     20 import android.content.ContentResolver;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.database.ContentObserver;
     24 import android.os.AsyncResult;
     25 import android.os.Build;
     26 import android.os.Handler;
     27 import android.os.Message;
     28 import android.os.PowerManager;
     29 import android.os.Registrant;
     30 import android.os.RegistrantList;
     31 import android.os.SystemClock;
     32 import android.os.SystemProperties;
     33 import android.os.UserHandle;
     34 import android.provider.Settings;
     35 import android.provider.Settings.SettingNotFoundException;
     36 import android.telephony.CellInfo;
     37 import android.telephony.CellInfoCdma;
     38 import android.telephony.Rlog;
     39 import android.telephony.ServiceState;
     40 import android.telephony.SignalStrength;
     41 import android.telephony.cdma.CdmaCellLocation;
     42 import android.text.TextUtils;
     43 import android.util.EventLog;
     44 import android.util.TimeUtils;
     45 
     46 import com.android.internal.telephony.CommandException;
     47 import com.android.internal.telephony.CommandsInterface;
     48 import com.android.internal.telephony.CommandsInterface.RadioState;
     49 import com.android.internal.telephony.EventLogTags;
     50 import com.android.internal.telephony.MccTable;
     51 import com.android.internal.telephony.Phone;
     52 import com.android.internal.telephony.PhoneConstants;
     53 import com.android.internal.telephony.ServiceStateTracker;
     54 import com.android.internal.telephony.TelephonyIntents;
     55 import com.android.internal.telephony.TelephonyProperties;
     56 import com.android.internal.telephony.dataconnection.DcTrackerBase;
     57 import com.android.internal.telephony.uicc.UiccCardApplication;
     58 import com.android.internal.telephony.uicc.UiccController;
     59 
     60 import java.io.FileDescriptor;
     61 import java.io.PrintWriter;
     62 import java.util.Arrays;
     63 import java.util.Calendar;
     64 import java.util.Date;
     65 import java.util.List;
     66 import java.util.TimeZone;
     67 
     68 /**
     69  * {@hide}
     70  */
     71 public class CdmaServiceStateTracker extends ServiceStateTracker {
     72     static final String LOG_TAG = "CdmaSST";
     73 
     74     CDMAPhone mPhone;
     75     CdmaCellLocation mCellLoc;
     76     CdmaCellLocation mNewCellLoc;
     77 
     78     // Min values used to by getOtasp()
     79     private static final String UNACTIVATED_MIN2_VALUE = "000000";
     80     private static final String UNACTIVATED_MIN_VALUE = "1111110111";
     81 
     82     // Current Otasp value
     83     int mCurrentOtaspMode = OTASP_UNINITIALIZED;
     84 
     85      /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */
     86     private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
     87     private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
     88             NITZ_UPDATE_SPACING_DEFAULT);
     89 
     90     /** If mNitzUpdateSpacing hasn't been exceeded but update is > mNitzUpdate do the update */
     91     private static final int NITZ_UPDATE_DIFF_DEFAULT = 2000;
     92     private int mNitzUpdateDiff = SystemProperties.getInt("ro.nitz_update_diff",
     93             NITZ_UPDATE_DIFF_DEFAULT);
     94 
     95     private boolean mCdmaRoaming = false;
     96     private int mRoamingIndicator;
     97     private boolean mIsInPrl;
     98     private int mDefaultRoamingIndicator;
     99 
    100     /**
    101      * Initially assume no data connection.
    102      */
    103     protected int mRegistrationState = -1;
    104     protected RegistrantList mCdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
    105 
    106     /**
    107      * Sometimes we get the NITZ time before we know what country we
    108      * are in. Keep the time zone information from the NITZ string so
    109      * we can fix the time zone once know the country.
    110      */
    111     protected boolean mNeedFixZone = false;
    112     private int mZoneOffset;
    113     private boolean mZoneDst;
    114     private long mZoneTime;
    115     protected boolean mGotCountryCode = false;
    116     String mSavedTimeZone;
    117     long mSavedTime;
    118     long mSavedAtTime;
    119 
    120     /** Wake lock used while setting time of day. */
    121     private PowerManager.WakeLock mWakeLock;
    122     private static final String WAKELOCK_TAG = "ServiceStateTracker";
    123 
    124     /** Contains the name of the registered network in CDMA (either ONS or ERI text). */
    125     protected String mCurPlmn = null;
    126 
    127     protected String mMdn;
    128     protected int mHomeSystemId[] = null;
    129     protected int mHomeNetworkId[] = null;
    130     protected String mMin;
    131     protected String mPrlVersion;
    132     protected boolean mIsMinInfoReady = false;
    133 
    134     private boolean mIsEriTextLoaded = false;
    135     protected boolean mIsSubscriptionFromRuim = false;
    136     private CdmaSubscriptionSourceManager mCdmaSSM;
    137 
    138     /* Used only for debugging purposes. */
    139     private String mRegistrationDeniedReason;
    140 
    141     private ContentResolver mCr;
    142     private String mCurrentCarrier = null;
    143 
    144     private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
    145         @Override
    146         public void onChange(boolean selfChange) {
    147             if (DBG) log("Auto time state changed");
    148             revertToNitzTime();
    149         }
    150     };
    151 
    152     private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
    153         @Override
    154         public void onChange(boolean selfChange) {
    155             if (DBG) log("Auto time zone state changed");
    156             revertToNitzTimeZone();
    157         }
    158     };
    159 
    160     public CdmaServiceStateTracker(CDMAPhone phone) {
    161         this(phone, new CellInfoCdma());
    162     }
    163 
    164     protected CdmaServiceStateTracker(CDMAPhone phone, CellInfo cellInfo) {
    165         super(phone, phone.mCi, cellInfo);
    166 
    167         mPhone = phone;
    168         mCr = phone.getContext().getContentResolver();
    169         mCellLoc = new CdmaCellLocation();
    170         mNewCellLoc = new CdmaCellLocation();
    171 
    172         mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(phone.getContext(), mCi, this,
    173                 EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
    174         mIsSubscriptionFromRuim = (mCdmaSSM.getCdmaSubscriptionSource() ==
    175                           CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM);
    176 
    177         PowerManager powerManager =
    178                 (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
    179         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
    180 
    181         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
    182 
    183         mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED_CDMA, null);
    184         mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
    185 
    186         mCi.registerForCdmaPrlChanged(this, EVENT_CDMA_PRL_VERSION_CHANGED, null);
    187         phone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null);
    188         mCi.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null);
    189 
    190         // System setting property AIRPLANE_MODE_ON is set in Settings.
    191         int airplaneMode = Settings.Global.getInt(mCr, Settings.Global.AIRPLANE_MODE_ON, 0);
    192         mDesiredPowerState = ! (airplaneMode > 0);
    193 
    194         mCr.registerContentObserver(
    195                 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
    196                 mAutoTimeObserver);
    197         mCr.registerContentObserver(
    198             Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
    199             mAutoTimeZoneObserver);
    200         setSignalStrengthDefaultValues();
    201     }
    202 
    203     @Override
    204     public void dispose() {
    205         checkCorrectThread();
    206         log("ServiceStateTracker dispose");
    207 
    208         // Unregister for all events.
    209         mCi.unregisterForRadioStateChanged(this);
    210         mCi.unregisterForVoiceNetworkStateChanged(this);
    211         mCi.unregisterForCdmaOtaProvision(this);
    212         mPhone.unregisterForEriFileLoaded(this);
    213         if (mUiccApplcation != null) {mUiccApplcation.unregisterForReady(this);}
    214         if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
    215         mCi.unSetOnNITZTime(this);
    216         mCr.unregisterContentObserver(mAutoTimeObserver);
    217         mCr.unregisterContentObserver(mAutoTimeZoneObserver);
    218         mCdmaSSM.dispose(this);
    219         mCi.unregisterForCdmaPrlChanged(this);
    220         super.dispose();
    221     }
    222 
    223     @Override
    224     protected void finalize() {
    225         if (DBG) log("CdmaServiceStateTracker finalized");
    226     }
    227 
    228     /**
    229      * Registration point for subscription info ready
    230      * @param h handler to notify
    231      * @param what what code of message when delivered
    232      * @param obj placed in Message.obj
    233      */
    234     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
    235         Registrant r = new Registrant(h, what, obj);
    236         mCdmaForSubscriptionInfoReadyRegistrants.add(r);
    237 
    238         if (isMinInfoReady()) {
    239             r.notifyRegistrant();
    240         }
    241     }
    242 
    243     public void unregisterForSubscriptionInfoReady(Handler h) {
    244         mCdmaForSubscriptionInfoReadyRegistrants.remove(h);
    245     }
    246 
    247     /**
    248      * Save current source of cdma subscription
    249      * @param source - 1 for NV, 0 for RUIM
    250      */
    251     private void saveCdmaSubscriptionSource(int source) {
    252         log("Storing cdma subscription source: " + source);
    253         Settings.Global.putInt(mPhone.getContext().getContentResolver(),
    254                 Settings.Global.CDMA_SUBSCRIPTION_MODE,
    255                 source );
    256     }
    257 
    258     private void getSubscriptionInfoAndStartPollingThreads() {
    259         mCi.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
    260 
    261         // Get Registration Information
    262         pollState();
    263     }
    264 
    265     @Override
    266     public void handleMessage (Message msg) {
    267         AsyncResult ar;
    268         int[] ints;
    269         String[] strings;
    270 
    271         if (!mPhone.mIsTheCurrentActivePhone) {
    272             loge("Received message " + msg + "[" + msg.what + "]" +
    273                     " while being destroyed. Ignoring.");
    274             return;
    275         }
    276 
    277         switch (msg.what) {
    278         case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
    279             handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource());
    280             break;
    281 
    282         case EVENT_RUIM_READY:
    283             // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
    284             // cm.setCurrentPreferredNetworkType();
    285 
    286             if (mPhone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
    287                 // Subscription will be read from SIM I/O
    288                 if (DBG) log("Receive EVENT_RUIM_READY");
    289                 pollState();
    290             } else {
    291                 if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
    292                 getSubscriptionInfoAndStartPollingThreads();
    293             }
    294             mPhone.prepareEri();
    295             break;
    296 
    297         case EVENT_NV_READY:
    298             updatePhoneObject();
    299 
    300             // For Non-RUIM phones, the subscription information is stored in
    301             // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA
    302             // subscription info.
    303             getSubscriptionInfoAndStartPollingThreads();
    304             break;
    305 
    306         case EVENT_RADIO_STATE_CHANGED:
    307             if(mCi.getRadioState() == RadioState.RADIO_ON) {
    308                 handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource());
    309 
    310                 // Signal strength polling stops when radio is off.
    311                 queueNextSignalStrengthPoll();
    312             }
    313             // This will do nothing in the 'radio not available' case.
    314             setPowerStateToDesired();
    315             pollState();
    316             break;
    317 
    318         case EVENT_NETWORK_STATE_CHANGED_CDMA:
    319             pollState();
    320             break;
    321 
    322         case EVENT_GET_SIGNAL_STRENGTH:
    323             // This callback is called when signal strength is polled
    324             // all by itself.
    325 
    326             if (!(mCi.getRadioState().isOn())) {
    327                 // Polling will continue when radio turns back on.
    328                 return;
    329             }
    330             ar = (AsyncResult) msg.obj;
    331             onSignalStrengthResult(ar, false);
    332             queueNextSignalStrengthPoll();
    333 
    334             break;
    335 
    336         case EVENT_GET_LOC_DONE_CDMA:
    337             ar = (AsyncResult) msg.obj;
    338 
    339             if (ar.exception == null) {
    340                 String states[] = (String[])ar.result;
    341                 int baseStationId = -1;
    342                 int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG;
    343                 int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
    344                 int systemId = -1;
    345                 int networkId = -1;
    346 
    347                 if (states.length > 9) {
    348                     try {
    349                         if (states[4] != null) {
    350                             baseStationId = Integer.parseInt(states[4]);
    351                         }
    352                         if (states[5] != null) {
    353                             baseStationLatitude = Integer.parseInt(states[5]);
    354                         }
    355                         if (states[6] != null) {
    356                             baseStationLongitude = Integer.parseInt(states[6]);
    357                         }
    358                         // Some carriers only return lat-lngs of 0,0
    359                         if (baseStationLatitude == 0 && baseStationLongitude == 0) {
    360                             baseStationLatitude  = CdmaCellLocation.INVALID_LAT_LONG;
    361                             baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
    362                         }
    363                         if (states[8] != null) {
    364                             systemId = Integer.parseInt(states[8]);
    365                         }
    366                         if (states[9] != null) {
    367                             networkId = Integer.parseInt(states[9]);
    368                         }
    369                     } catch (NumberFormatException ex) {
    370                         loge("error parsing cell location data: " + ex);
    371                     }
    372                 }
    373 
    374                 mCellLoc.setCellLocationData(baseStationId, baseStationLatitude,
    375                         baseStationLongitude, systemId, networkId);
    376                 mPhone.notifyLocationChanged();
    377             }
    378 
    379             // Release any temporary cell lock, which could have been
    380             // acquired to allow a single-shot location update.
    381             disableSingleLocationUpdate();
    382             break;
    383 
    384         case EVENT_POLL_STATE_REGISTRATION_CDMA:
    385         case EVENT_POLL_STATE_OPERATOR_CDMA:
    386         case EVENT_POLL_STATE_GPRS:
    387             ar = (AsyncResult) msg.obj;
    388             handlePollStateResult(msg.what, ar);
    389             break;
    390 
    391         case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION
    392             ar = (AsyncResult) msg.obj;
    393 
    394             if (ar.exception == null) {
    395                 String cdmaSubscription[] = (String[])ar.result;
    396                 if (cdmaSubscription != null && cdmaSubscription.length >= 5) {
    397                     mMdn = cdmaSubscription[0];
    398                     parseSidNid(cdmaSubscription[1], cdmaSubscription[2]);
    399 
    400                     mMin = cdmaSubscription[3];
    401                     mPrlVersion = cdmaSubscription[4];
    402                     if (DBG) log("GET_CDMA_SUBSCRIPTION: MDN=" + mMdn);
    403 
    404                     mIsMinInfoReady = true;
    405 
    406                     updateOtaspState();
    407                     if (!mIsSubscriptionFromRuim && mIccRecords != null) {
    408                         if (DBG) {
    409                             log("GET_CDMA_SUBSCRIPTION set imsi in mIccRecords");
    410                         }
    411                         mIccRecords.setImsi(getImsi());
    412                     } else {
    413                         if (DBG) {
    414                             log("GET_CDMA_SUBSCRIPTION either mIccRecords is null  or NV type device" +
    415                                     " - not setting Imsi in mIccRecords");
    416                         }
    417                     }
    418                 } else {
    419                     if (DBG) {
    420                         log("GET_CDMA_SUBSCRIPTION: error parsing cdmaSubscription params num="
    421                             + cdmaSubscription.length);
    422                     }
    423                 }
    424             }
    425             break;
    426 
    427         case EVENT_POLL_SIGNAL_STRENGTH:
    428             // Just poll signal strength...not part of pollState()
    429 
    430             mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
    431             break;
    432 
    433         case EVENT_NITZ_TIME:
    434             ar = (AsyncResult) msg.obj;
    435 
    436             String nitzString = (String)((Object[])ar.result)[0];
    437             long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
    438 
    439             setTimeFromNITZString(nitzString, nitzReceiveTime);
    440             break;
    441 
    442         case EVENT_SIGNAL_STRENGTH_UPDATE:
    443             // This is a notification from CommandsInterface.setOnSignalStrengthUpdate.
    444 
    445             ar = (AsyncResult) msg.obj;
    446 
    447             // The radio is telling us about signal strength changes,
    448             // so we don't have to ask it.
    449             mDontPollSignalStrength = true;
    450 
    451             onSignalStrengthResult(ar, false);
    452             break;
    453 
    454         case EVENT_RUIM_RECORDS_LOADED:
    455             log("EVENT_RUIM_RECORDS_LOADED: what=" + msg.what);
    456             updatePhoneObject();
    457             updateSpnDisplay();
    458             break;
    459 
    460         case EVENT_LOCATION_UPDATES_ENABLED:
    461             ar = (AsyncResult) msg.obj;
    462 
    463             if (ar.exception == null) {
    464                 mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE_CDMA, null));
    465             }
    466             break;
    467 
    468         case EVENT_ERI_FILE_LOADED:
    469             // Repoll the state once the ERI file has been loaded.
    470             if (DBG) log("[CdmaServiceStateTracker] ERI file has been loaded, repolling.");
    471             pollState();
    472             break;
    473 
    474         case EVENT_OTA_PROVISION_STATUS_CHANGE:
    475             ar = (AsyncResult)msg.obj;
    476             if (ar.exception == null) {
    477                 ints = (int[]) ar.result;
    478                 int otaStatus = ints[0];
    479                 if (otaStatus == Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED
    480                     || otaStatus == Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) {
    481                     if (DBG) log("EVENT_OTA_PROVISION_STATUS_CHANGE: Complete, Reload MDN");
    482                     mCi.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
    483                 }
    484             }
    485             break;
    486 
    487         case EVENT_CDMA_PRL_VERSION_CHANGED:
    488             ar = (AsyncResult)msg.obj;
    489             if (ar.exception == null) {
    490                 ints = (int[]) ar.result;
    491                 mPrlVersion = Integer.toString(ints[0]);
    492             }
    493             break;
    494 
    495         default:
    496             super.handleMessage(msg);
    497         break;
    498         }
    499     }
    500 
    501     //***** Private Instance Methods
    502 
    503     private void handleCdmaSubscriptionSource(int newSubscriptionSource) {
    504         log("Subscription Source : " + newSubscriptionSource);
    505         mIsSubscriptionFromRuim =
    506             (newSubscriptionSource == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM);
    507         saveCdmaSubscriptionSource(newSubscriptionSource);
    508         if (!mIsSubscriptionFromRuim) {
    509             // NV is ready when subscription source is NV
    510             sendMessage(obtainMessage(EVENT_NV_READY));
    511         }
    512     }
    513 
    514     @Override
    515     protected void setPowerStateToDesired() {
    516         // If we want it on and it's off, turn it on
    517         if (mDesiredPowerState
    518             && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
    519             mCi.setRadioPower(true, null);
    520         } else if (!mDesiredPowerState && mCi.getRadioState().isOn()) {
    521             DcTrackerBase dcTracker = mPhone.mDcTracker;
    522 
    523             // If it's on and available and we want it off gracefully
    524             powerOffRadioSafely(dcTracker);
    525         } // Otherwise, we're in the desired state
    526     }
    527 
    528     @Override
    529     protected void updateSpnDisplay() {
    530         // mOperatorAlphaLong contains the ERI text
    531         String plmn = mSS.getOperatorAlphaLong();
    532         if (!TextUtils.equals(plmn, mCurPlmn)) {
    533             // Allow A blank plmn, "" to set showPlmn to true. Previously, we
    534             // would set showPlmn to true only if plmn was not empty, i.e. was not
    535             // null and not blank. But this would cause us to incorrectly display
    536             // "No Service". Now showPlmn is set to true for any non null string.
    537             boolean showPlmn = plmn != null;
    538             if (DBG) {
    539                 log(String.format("updateSpnDisplay: changed sending intent" +
    540                             " showPlmn='%b' plmn='%s'", showPlmn, plmn));
    541             }
    542             Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
    543             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    544             intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, false);
    545             intent.putExtra(TelephonyIntents.EXTRA_SPN, "");
    546             intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
    547             intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
    548             mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    549         }
    550 
    551         mCurPlmn = plmn;
    552     }
    553 
    554     @Override
    555     protected Phone getPhone() {
    556         return mPhone;
    557     }
    558 
    559     /**
    560     * Hanlde the PollStateResult message
    561     */
    562     protected void handlePollStateResultMessage(int what, AsyncResult ar){
    563         int ints[];
    564         String states[];
    565         switch (what) {
    566             case EVENT_POLL_STATE_GPRS: {
    567                 states = (String[])ar.result;
    568                 if (DBG) {
    569                     log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" +
    570                             states.length + " states=" + states);
    571                 }
    572 
    573                 int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
    574                 int dataRadioTechnology = 0;
    575 
    576                 if (states.length > 0) {
    577                     try {
    578                         regState = Integer.parseInt(states[0]);
    579 
    580                         // states[3] (if present) is the current radio technology
    581                         if (states.length >= 4 && states[3] != null) {
    582                             dataRadioTechnology = Integer.parseInt(states[3]);
    583                         }
    584                     } catch (NumberFormatException ex) {
    585                         loge("handlePollStateResultMessage: error parsing GprsRegistrationState: "
    586                                         + ex);
    587                     }
    588                 }
    589 
    590                 int dataRegState = regCodeToServiceState(regState);
    591                 mNewSS.setDataRegState(dataRegState);
    592                 mNewSS.setRilDataRadioTechnology(dataRadioTechnology);
    593                 if (DBG) {
    594                     log("handlPollStateResultMessage: cdma setDataRegState=" + dataRegState
    595                             + " regState=" + regState
    596                             + " dataRadioTechnology=" + dataRadioTechnology);
    597                 }
    598                 break;
    599             }
    600 
    601             case EVENT_POLL_STATE_REGISTRATION_CDMA: // Handle RIL_REQUEST_REGISTRATION_STATE.
    602                 states = (String[])ar.result;
    603 
    604                 int registrationState = 4;     //[0] registrationState
    605                 int radioTechnology = -1;      //[3] radioTechnology
    606                 int baseStationId = -1;        //[4] baseStationId
    607                 //[5] baseStationLatitude
    608                 int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG;
    609                 //[6] baseStationLongitude
    610                 int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
    611                 int cssIndicator = 0;          //[7] init with 0, because it is treated as a boolean
    612                 int systemId = 0;              //[8] systemId
    613                 int networkId = 0;             //[9] networkId
    614                 int roamingIndicator = -1;     //[10] Roaming indicator
    615                 int systemIsInPrl = 0;         //[11] Indicates if current system is in PRL
    616                 int defaultRoamingIndicator = 0;  //[12] Is default roaming indicator from PRL
    617                 int reasonForDenial = 0;       //[13] Denial reason if registrationState = 3
    618 
    619                 if (states.length >= 14) {
    620                     try {
    621                         if (states[0] != null) {
    622                             registrationState = Integer.parseInt(states[0]);
    623                         }
    624                         if (states[3] != null) {
    625                             radioTechnology = Integer.parseInt(states[3]);
    626                         }
    627                         if (states[4] != null) {
    628                             baseStationId = Integer.parseInt(states[4]);
    629                         }
    630                         if (states[5] != null) {
    631                             baseStationLatitude = Integer.parseInt(states[5]);
    632                         }
    633                         if (states[6] != null) {
    634                             baseStationLongitude = Integer.parseInt(states[6]);
    635                         }
    636                         // Some carriers only return lat-lngs of 0,0
    637                         if (baseStationLatitude == 0 && baseStationLongitude == 0) {
    638                             baseStationLatitude  = CdmaCellLocation.INVALID_LAT_LONG;
    639                             baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
    640                         }
    641                         if (states[7] != null) {
    642                             cssIndicator = Integer.parseInt(states[7]);
    643                         }
    644                         if (states[8] != null) {
    645                             systemId = Integer.parseInt(states[8]);
    646                         }
    647                         if (states[9] != null) {
    648                             networkId = Integer.parseInt(states[9]);
    649                         }
    650                         if (states[10] != null) {
    651                             roamingIndicator = Integer.parseInt(states[10]);
    652                         }
    653                         if (states[11] != null) {
    654                             systemIsInPrl = Integer.parseInt(states[11]);
    655                         }
    656                         if (states[12] != null) {
    657                             defaultRoamingIndicator = Integer.parseInt(states[12]);
    658                         }
    659                         if (states[13] != null) {
    660                             reasonForDenial = Integer.parseInt(states[13]);
    661                         }
    662                     } catch (NumberFormatException ex) {
    663                         loge("EVENT_POLL_STATE_REGISTRATION_CDMA: error parsing: " + ex);
    664                     }
    665                 } else {
    666                     throw new RuntimeException("Warning! Wrong number of parameters returned from "
    667                                          + "RIL_REQUEST_REGISTRATION_STATE: expected 14 or more "
    668                                          + "strings and got " + states.length + " strings");
    669                 }
    670 
    671                 mRegistrationState = registrationState;
    672                 // When registration state is roaming and TSB58
    673                 // roaming indicator is not in the carrier-specified
    674                 // list of ERIs for home system, mCdmaRoaming is true.
    675                 mCdmaRoaming =
    676                         regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
    677                 mNewSS.setState (regCodeToServiceState(registrationState));
    678 
    679                 mNewSS.setRilVoiceRadioTechnology(radioTechnology);
    680 
    681                 mNewSS.setCssIndicator(cssIndicator);
    682                 mNewSS.setSystemAndNetworkId(systemId, networkId);
    683                 mRoamingIndicator = roamingIndicator;
    684                 mIsInPrl = (systemIsInPrl == 0) ? false : true;
    685                 mDefaultRoamingIndicator = defaultRoamingIndicator;
    686 
    687 
    688                 // Values are -1 if not available.
    689                 mNewCellLoc.setCellLocationData(baseStationId, baseStationLatitude,
    690                         baseStationLongitude, systemId, networkId);
    691 
    692                 if (reasonForDenial == 0) {
    693                     mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_GEN;
    694                 } else if (reasonForDenial == 1) {
    695                     mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_AUTH;
    696                 } else {
    697                     mRegistrationDeniedReason = "";
    698                 }
    699 
    700                 if (mRegistrationState == 3) {
    701                     if (DBG) log("Registration denied, " + mRegistrationDeniedReason);
    702                 }
    703                 break;
    704 
    705             case EVENT_POLL_STATE_OPERATOR_CDMA: // Handle RIL_REQUEST_OPERATOR
    706                 String opNames[] = (String[])ar.result;
    707 
    708                 if (opNames != null && opNames.length >= 3) {
    709                     // If the NUMERIC field isn't valid use PROPERTY_CDMA_HOME_OPERATOR_NUMERIC
    710                     if ((opNames[2] == null) || (opNames[2].length() < 5)
    711                             || ("00000".equals(opNames[2]))) {
    712                         opNames[2] = SystemProperties.get(
    713                                 CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC, "00000");
    714                         if (DBG) {
    715                             log("RIL_REQUEST_OPERATOR.response[2], the numeric, " +
    716                                     " is bad. Using SystemProperties '" +
    717                                             CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC +
    718                                     "'= " + opNames[2]);
    719                         }
    720                     }
    721 
    722                     if (!mIsSubscriptionFromRuim) {
    723                         // In CDMA in case on NV, the ss.mOperatorAlphaLong is set later with the
    724                         // ERI text, so here it is ignored what is coming from the modem.
    725                         mNewSS.setOperatorName(null, opNames[1], opNames[2]);
    726                     } else {
    727                         mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
    728                     }
    729                 } else {
    730                     if (DBG) log("EVENT_POLL_STATE_OPERATOR_CDMA: error parsing opNames");
    731                 }
    732                 break;
    733 
    734 
    735             default:
    736 
    737 
    738                 loge("handlePollStateResultMessage: RIL response handle in wrong phone!"
    739                         + " Expected CDMA RIL request and get GSM RIL request.");
    740                 break;
    741         }
    742     }
    743 
    744     /**
    745      * Handle the result of one of the pollState() - related requests
    746      */
    747     @Override
    748     protected void handlePollStateResult(int what, AsyncResult ar) {
    749         // Ignore stale requests from last poll.
    750         if (ar.userObj != mPollingContext) return;
    751 
    752         if (ar.exception != null) {
    753             CommandException.Error err=null;
    754 
    755             if (ar.exception instanceof CommandException) {
    756                 err = ((CommandException)(ar.exception)).getCommandError();
    757             }
    758 
    759             if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
    760                 // Radio has crashed or turned off.
    761                 cancelPollState();
    762                 return;
    763             }
    764 
    765             if (!mCi.getRadioState().isOn()) {
    766                 // Radio has crashed or turned off.
    767                 cancelPollState();
    768                 return;
    769             }
    770 
    771             if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
    772                 loge("handlePollStateResult: RIL returned an error where it must succeed"
    773                         + ar.exception);
    774             }
    775         } else try {
    776             handlePollStateResultMessage(what, ar);
    777         } catch (RuntimeException ex) {
    778             loge("handlePollStateResult: Exception while polling service state. "
    779                     + "Probably malformed RIL response." + ex);
    780         }
    781 
    782         mPollingContext[0]--;
    783 
    784         if (mPollingContext[0] == 0) {
    785             boolean namMatch = false;
    786             if (!isSidsAllZeros() && isHomeSid(mNewSS.getSystemId())) {
    787                 namMatch = true;
    788             }
    789 
    790             // Setting SS Roaming (general)
    791             if (mIsSubscriptionFromRuim) {
    792                 mNewSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, mNewSS));
    793             } else {
    794                 mNewSS.setRoaming(mCdmaRoaming);
    795             }
    796 
    797             // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
    798             mNewSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
    799             mNewSS.setCdmaRoamingIndicator(mRoamingIndicator);
    800             boolean isPrlLoaded = true;
    801             if (TextUtils.isEmpty(mPrlVersion)) {
    802                 isPrlLoaded = false;
    803             }
    804             if (!isPrlLoaded || (mNewSS.getRilVoiceRadioTechnology()
    805                                         == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
    806                 log("Turn off roaming indicator if !isPrlLoaded or voice RAT is unknown");
    807                 mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
    808             } else if (!isSidsAllZeros()) {
    809                 if (!namMatch && !mIsInPrl) {
    810                     // Use default
    811                     mNewSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator);
    812                 } else if (namMatch && !mIsInPrl) {
    813                     // TODO this will be removed when we handle roaming on LTE on CDMA+LTE phones
    814                     if (mNewSS.getRilVoiceRadioTechnology()
    815                             == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) {
    816                         log("Turn off roaming indicator as voice is LTE");
    817                         mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
    818                     } else {
    819                         mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
    820                     }
    821                 } else if (!namMatch && mIsInPrl) {
    822                     // Use the one from PRL/ERI
    823                     mNewSS.setCdmaRoamingIndicator(mRoamingIndicator);
    824                 } else {
    825                     // It means namMatch && mIsInPrl
    826                     if ((mRoamingIndicator <= 2)) {
    827                         mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
    828                     } else {
    829                         // Use the one from PRL/ERI
    830                         mNewSS.setCdmaRoamingIndicator(mRoamingIndicator);
    831                     }
    832                 }
    833             }
    834 
    835             int roamingIndicator = mNewSS.getCdmaRoamingIndicator();
    836             mNewSS.setCdmaEriIconIndex(mPhone.mEriManager.getCdmaEriIconIndex(roamingIndicator,
    837                     mDefaultRoamingIndicator));
    838             mNewSS.setCdmaEriIconMode(mPhone.mEriManager.getCdmaEriIconMode(roamingIndicator,
    839                     mDefaultRoamingIndicator));
    840 
    841             // NOTE: Some operator may require overriding mCdmaRoaming
    842             // (set by the modem), depending on the mRoamingIndicator.
    843 
    844             if (DBG) {
    845                 log("Set CDMA Roaming Indicator to: " + mNewSS.getCdmaRoamingIndicator()
    846                     + ". mCdmaRoaming = " + mCdmaRoaming + ", isPrlLoaded = " + isPrlLoaded
    847                     + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl
    848                     + ", mRoamingIndicator = " + mRoamingIndicator
    849                     + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator);
    850             }
    851             pollStateDone();
    852         }
    853 
    854     }
    855 
    856     protected void setSignalStrengthDefaultValues() {
    857         mSignalStrength = new SignalStrength( false);
    858     }
    859 
    860     /**
    861      * A complete "service state" from our perspective is
    862      * composed of a handful of separate requests to the radio.
    863      *
    864      * We make all of these requests at once, but then abandon them
    865      * and start over again if the radio notifies us that some
    866      * event has changed
    867      */
    868     protected void
    869     pollState() {
    870         mPollingContext = new int[1];
    871         mPollingContext[0] = 0;
    872 
    873         switch (mCi.getRadioState()) {
    874         case RADIO_UNAVAILABLE:
    875             mNewSS.setStateOutOfService();
    876             mNewCellLoc.setStateInvalid();
    877             setSignalStrengthDefaultValues();
    878             mGotCountryCode = false;
    879 
    880             pollStateDone();
    881             break;
    882 
    883         case RADIO_OFF:
    884             mNewSS.setStateOff();
    885             mNewCellLoc.setStateInvalid();
    886             setSignalStrengthDefaultValues();
    887             mGotCountryCode = false;
    888 
    889             pollStateDone();
    890             break;
    891 
    892         default:
    893             // Issue all poll-related commands at once, then count
    894             // down the responses which are allowed to arrive
    895             // out-of-order.
    896 
    897             mPollingContext[0]++;
    898             // RIL_REQUEST_OPERATOR is necessary for CDMA
    899             mCi.getOperator(
    900                     obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, mPollingContext));
    901 
    902             mPollingContext[0]++;
    903             // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA
    904             mCi.getVoiceRegistrationState(
    905                     obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, mPollingContext));
    906 
    907             mPollingContext[0]++;
    908             // RIL_REQUEST_DATA_REGISTRATION_STATE
    909             mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS,
    910                                         mPollingContext));
    911             break;
    912         }
    913     }
    914 
    915     protected void fixTimeZone(String isoCountryCode) {
    916         TimeZone zone = null;
    917         // If the offset is (0, false) and the time zone property
    918         // is set, use the time zone property rather than GMT.
    919         String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
    920         if (DBG) {
    921             log("fixTimeZone zoneName='" + zoneName +
    922                 "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
    923                 " iso-cc='" + isoCountryCode +
    924                 "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode));
    925         }
    926         if ((mZoneOffset == 0) && (mZoneDst == false) && (zoneName != null)
    927                 && (zoneName.length() > 0)
    928                 && (Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode) < 0)) {
    929             // For NITZ string without time zone,
    930             // need adjust time to reflect default time zone setting
    931             zone = TimeZone.getDefault();
    932             if (mNeedFixZone) {
    933                 long ctm = System.currentTimeMillis();
    934                 long tzOffset = zone.getOffset(ctm);
    935                 if (DBG) {
    936                     log("fixTimeZone: tzOffset=" + tzOffset +
    937                             " ltod=" + TimeUtils.logTimeOfDay(ctm));
    938                 }
    939                 if (getAutoTime()) {
    940                     long adj = ctm - tzOffset;
    941                     if (DBG) log("fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj));
    942                     setAndBroadcastNetworkSetTime(adj);
    943                 } else {
    944                     // Adjust the saved NITZ time to account for tzOffset.
    945                     mSavedTime = mSavedTime - tzOffset;
    946                     if (DBG) log("fixTimeZone: adj mSavedTime=" + mSavedTime);
    947                 }
    948             }
    949             if (DBG) log("fixTimeZone: using default TimeZone");
    950         } else if (isoCountryCode.equals("")) {
    951             // Country code not found. This is likely a test network.
    952             // Get a TimeZone based only on the NITZ parameters (best guess).
    953             zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
    954             if (DBG) log("fixTimeZone: using NITZ TimeZone");
    955         } else {
    956             zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, isoCountryCode);
    957             if (DBG) log("fixTimeZone: using getTimeZone(off, dst, time, iso)");
    958         }
    959 
    960         mNeedFixZone = false;
    961 
    962         if (zone != null) {
    963             log("fixTimeZone: zone != null zone.getID=" + zone.getID());
    964             if (getAutoTimeZone()) {
    965                 setAndBroadcastNetworkSetTimeZone(zone.getID());
    966             } else {
    967                 log("fixTimeZone: skip changing zone as getAutoTimeZone was false");
    968             }
    969             saveNitzTimeZone(zone.getID());
    970         } else {
    971             log("fixTimeZone: zone == null, do nothing for zone");
    972         }
    973     }
    974 
    975     protected void pollStateDone() {
    976         if (DBG) log("pollStateDone: cdma oldSS=[" + mSS + "] newSS=[" + mNewSS + "]");
    977 
    978         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
    979             mNewSS.setRoaming(true);
    980         }
    981 
    982         useDataRegStateForDataOnlyDevices();
    983 
    984         boolean hasRegistered =
    985             mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
    986             && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
    987 
    988         boolean hasDeregistered =
    989             mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
    990             && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
    991 
    992         boolean hasCdmaDataConnectionAttached =
    993             mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
    994             && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
    995 
    996         boolean hasCdmaDataConnectionDetached =
    997             mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
    998             && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
    999 
   1000         boolean hasCdmaDataConnectionChanged =
   1001                        mSS.getDataRegState() != mNewSS.getDataRegState();
   1002 
   1003         boolean hasRilVoiceRadioTechnologyChanged =
   1004                 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
   1005 
   1006         boolean hasRilDataRadioTechnologyChanged =
   1007                 mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
   1008 
   1009         boolean hasChanged = !mNewSS.equals(mSS);
   1010 
   1011         boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
   1012 
   1013         boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
   1014 
   1015         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
   1016 
   1017         // Add an event log when connection state changes
   1018         if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState() ||
   1019                 mSS.getDataRegState() != mNewSS.getDataRegState()) {
   1020             EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE,
   1021                     mSS.getVoiceRegState(), mSS.getDataRegState(),
   1022                     mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
   1023         }
   1024 
   1025         ServiceState tss;
   1026         tss = mSS;
   1027         mSS = mNewSS;
   1028         mNewSS = tss;
   1029         // clean slate for next time
   1030         mNewSS.setStateOutOfService();
   1031 
   1032         CdmaCellLocation tcl = mCellLoc;
   1033         mCellLoc = mNewCellLoc;
   1034         mNewCellLoc = tcl;
   1035 
   1036         if (hasRilVoiceRadioTechnologyChanged) {
   1037             updatePhoneObject();
   1038         }
   1039 
   1040         if (hasRilDataRadioTechnologyChanged) {
   1041             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
   1042                     ServiceState.rilRadioTechnologyToString(mSS.getRilDataRadioTechnology()));
   1043         }
   1044 
   1045         if (hasRegistered) {
   1046             mNetworkAttachedRegistrants.notifyRegistrants();
   1047         }
   1048 
   1049         if (hasChanged) {
   1050             if ((mCi.getRadioState().isOn()) && (!mIsSubscriptionFromRuim)) {
   1051                 String eriText;
   1052                 // Now the CDMAPhone sees the new ServiceState so it can get the new ERI text
   1053                 if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
   1054                     eriText = mPhone.getCdmaEriText();
   1055                 } else {
   1056                     // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used for
   1057                     // mRegistrationState 0,2,3 and 4
   1058                     eriText = mPhone.getContext().getText(
   1059                             com.android.internal.R.string.roamingTextSearching).toString();
   1060                 }
   1061                 mSS.setOperatorAlphaLong(eriText);
   1062             }
   1063 
   1064             String operatorNumeric;
   1065 
   1066             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
   1067                     mSS.getOperatorAlphaLong());
   1068 
   1069             String prevOperatorNumeric =
   1070                     SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
   1071             operatorNumeric = mSS.getOperatorNumeric();
   1072             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
   1073             updateCarrierMccMncConfiguration(operatorNumeric,
   1074                     prevOperatorNumeric, mPhone.getContext());
   1075             if (operatorNumeric == null) {
   1076                 if (DBG) log("operatorNumeric is null");
   1077                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
   1078                 mGotCountryCode = false;
   1079             } else {
   1080                 String isoCountryCode = "";
   1081                 String mcc = operatorNumeric.substring(0, 3);
   1082                 try{
   1083                     isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(
   1084                             operatorNumeric.substring(0,3)));
   1085                 } catch ( NumberFormatException ex){
   1086                     loge("pollStateDone: countryCodeForMcc error" + ex);
   1087                 } catch ( StringIndexOutOfBoundsException ex) {
   1088                     loge("pollStateDone: countryCodeForMcc error" + ex);
   1089                 }
   1090 
   1091                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
   1092                         isoCountryCode);
   1093                 mGotCountryCode = true;
   1094 
   1095                 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
   1096                         mNeedFixZone)) {
   1097                     fixTimeZone(isoCountryCode);
   1098                 }
   1099             }
   1100 
   1101             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
   1102                     mSS.getRoaming() ? "true" : "false");
   1103 
   1104             updateSpnDisplay();
   1105             mPhone.notifyServiceStateChanged(mSS);
   1106         }
   1107 
   1108         if (hasCdmaDataConnectionAttached) {
   1109             mAttachedRegistrants.notifyRegistrants();
   1110         }
   1111 
   1112         if (hasCdmaDataConnectionDetached) {
   1113             mDetachedRegistrants.notifyRegistrants();
   1114         }
   1115 
   1116         if (hasCdmaDataConnectionChanged || hasRilDataRadioTechnologyChanged) {
   1117             notifyDataRegStateRilRadioTechnologyChanged();
   1118             mPhone.notifyDataConnection(null);
   1119         }
   1120 
   1121         if (hasRoamingOn) {
   1122             mRoamingOnRegistrants.notifyRegistrants();
   1123         }
   1124 
   1125         if (hasRoamingOff) {
   1126             mRoamingOffRegistrants.notifyRegistrants();
   1127         }
   1128 
   1129         if (hasLocationChanged) {
   1130             mPhone.notifyLocationChanged();
   1131         }
   1132         // TODO: Add CdmaCellIdenity updating, see CdmaLteServiceStateTracker.
   1133     }
   1134 
   1135     /**
   1136      * Returns a TimeZone object based only on parameters from the NITZ string.
   1137      */
   1138     private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
   1139         TimeZone guess = findTimeZone(offset, dst, when);
   1140         if (guess == null) {
   1141             // Couldn't find a proper timezone.  Perhaps the DST data is wrong.
   1142             guess = findTimeZone(offset, !dst, when);
   1143         }
   1144         if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID()));
   1145         return guess;
   1146     }
   1147 
   1148     private TimeZone findTimeZone(int offset, boolean dst, long when) {
   1149         int rawOffset = offset;
   1150         if (dst) {
   1151             rawOffset -= 3600000;
   1152         }
   1153         String[] zones = TimeZone.getAvailableIDs(rawOffset);
   1154         TimeZone guess = null;
   1155         Date d = new Date(when);
   1156         for (String zone : zones) {
   1157             TimeZone tz = TimeZone.getTimeZone(zone);
   1158             if (tz.getOffset(when) == offset &&
   1159                     tz.inDaylightTime(d) == dst) {
   1160                 guess = tz;
   1161                 break;
   1162             }
   1163         }
   1164 
   1165         return guess;
   1166     }
   1167 
   1168     /**
   1169      * TODO: This code is exactly the same as in GsmServiceStateTracker
   1170      * and has a TODO to not poll signal strength if screen is off.
   1171      * This code should probably be hoisted to the base class so
   1172      * the fix, when added, works for both.
   1173      */
   1174     private void
   1175     queueNextSignalStrengthPoll() {
   1176         if (mDontPollSignalStrength) {
   1177             // The radio is telling us about signal strength changes
   1178             // we don't have to ask it
   1179             return;
   1180         }
   1181 
   1182         Message msg;
   1183 
   1184         msg = obtainMessage();
   1185         msg.what = EVENT_POLL_SIGNAL_STRENGTH;
   1186 
   1187         // TODO Don't poll signal strength if screen is off
   1188         sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
   1189     }
   1190 
   1191     protected int radioTechnologyToDataServiceState(int code) {
   1192         int retVal = ServiceState.STATE_OUT_OF_SERVICE;
   1193         switch(code) {
   1194         case 0:
   1195         case 1:
   1196         case 2:
   1197         case 3:
   1198         case 4:
   1199         case 5:
   1200             break;
   1201         case 6: // RADIO_TECHNOLOGY_1xRTT
   1202         case 7: // RADIO_TECHNOLOGY_EVDO_0
   1203         case 8: // RADIO_TECHNOLOGY_EVDO_A
   1204         case 12: // RADIO_TECHNOLOGY_EVDO_B
   1205         case 13: // RADIO_TECHNOLOGY_EHRPD
   1206             retVal = ServiceState.STATE_IN_SERVICE;
   1207             break;
   1208         default:
   1209             loge("radioTechnologyToDataServiceState: Wrong radioTechnology code.");
   1210         break;
   1211         }
   1212         return(retVal);
   1213     }
   1214 
   1215     /** code is registration state 0-5 from TS 27.007 7.2 */
   1216     protected int
   1217     regCodeToServiceState(int code) {
   1218         switch (code) {
   1219         case 0: // Not searching and not registered
   1220             return ServiceState.STATE_OUT_OF_SERVICE;
   1221         case 1:
   1222             return ServiceState.STATE_IN_SERVICE;
   1223         case 2: // 2 is "searching", fall through
   1224         case 3: // 3 is "registration denied", fall through
   1225         case 4: // 4 is "unknown", not valid in current baseband
   1226             return ServiceState.STATE_OUT_OF_SERVICE;
   1227         case 5:// 5 is "Registered, roaming"
   1228             return ServiceState.STATE_IN_SERVICE;
   1229 
   1230         default:
   1231             loge("regCodeToServiceState: unexpected service state " + code);
   1232         return ServiceState.STATE_OUT_OF_SERVICE;
   1233         }
   1234     }
   1235 
   1236     @Override
   1237     public int getCurrentDataConnectionState() {
   1238         return mSS.getDataRegState();
   1239     }
   1240 
   1241     /**
   1242      * code is registration state 0-5 from TS 27.007 7.2
   1243      * returns true if registered roam, false otherwise
   1244      */
   1245     private boolean
   1246     regCodeIsRoaming (int code) {
   1247         // 5 is  "in service -- roam"
   1248         return 5 == code;
   1249     }
   1250 
   1251     /**
   1252      * Determine whether a roaming indicator is in the carrier-specified list of ERIs for
   1253      * home system
   1254      *
   1255      * @param roamInd roaming indicator in String
   1256      * @return true if the roamInd is in the carrier-specified list of ERIs for home network
   1257      */
   1258     private boolean isRoamIndForHomeSystem(String roamInd) {
   1259         // retrieve the carrier-specified list of ERIs for home system
   1260         String homeRoamIndicators = SystemProperties.get("ro.cdma.homesystem");
   1261 
   1262         if (!TextUtils.isEmpty(homeRoamIndicators)) {
   1263             // searches through the comma-separated list for a match,
   1264             // return true if one is found.
   1265             for (String homeRoamInd : homeRoamIndicators.split(",")) {
   1266                 if (homeRoamInd.equals(roamInd)) {
   1267                     return true;
   1268                 }
   1269             }
   1270             // no matches found against the list!
   1271             return false;
   1272         }
   1273 
   1274         // no system property found for the roaming indicators for home system
   1275         return false;
   1276     }
   1277 
   1278     /**
   1279      * Set roaming state when cdmaRoaming is true and ons is different from spn
   1280      * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming
   1281      * @param s ServiceState hold current ons
   1282      * @return true for roaming state set
   1283      */
   1284     private
   1285     boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) {
   1286         String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty");
   1287 
   1288         // NOTE: in case of RUIM we should completely ignore the ERI data file and
   1289         // mOperatorAlphaLong is set from RIL_REQUEST_OPERATOR response 0 (alpha ONS)
   1290         String onsl = s.getOperatorAlphaLong();
   1291         String onss = s.getOperatorAlphaShort();
   1292 
   1293         boolean equalsOnsl = onsl != null && spn.equals(onsl);
   1294         boolean equalsOnss = onss != null && spn.equals(onss);
   1295 
   1296         return cdmaRoaming && !(equalsOnsl || equalsOnss);
   1297     }
   1298 
   1299 
   1300     /**
   1301      * nitzReceiveTime is time_t that the NITZ time was posted
   1302      */
   1303 
   1304     private
   1305     void setTimeFromNITZString (String nitz, long nitzReceiveTime)
   1306     {
   1307         // "yy/mm/dd,hh:mm:ss(+/-)tz"
   1308         // tz is in number of quarter-hours
   1309 
   1310         long start = SystemClock.elapsedRealtime();
   1311         if (DBG) {
   1312             log("NITZ: " + nitz + "," + nitzReceiveTime +
   1313                         " start=" + start + " delay=" + (start - nitzReceiveTime));
   1314         }
   1315 
   1316         try {
   1317             /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
   1318              * offset as well (which we won't worry about until later) */
   1319             Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
   1320 
   1321             c.clear();
   1322             c.set(Calendar.DST_OFFSET, 0);
   1323 
   1324             String[] nitzSubs = nitz.split("[/:,+-]");
   1325 
   1326             int year = 2000 + Integer.parseInt(nitzSubs[0]);
   1327             c.set(Calendar.YEAR, year);
   1328 
   1329             // month is 0 based!
   1330             int month = Integer.parseInt(nitzSubs[1]) - 1;
   1331             c.set(Calendar.MONTH, month);
   1332 
   1333             int date = Integer.parseInt(nitzSubs[2]);
   1334             c.set(Calendar.DATE, date);
   1335 
   1336             int hour = Integer.parseInt(nitzSubs[3]);
   1337             c.set(Calendar.HOUR, hour);
   1338 
   1339             int minute = Integer.parseInt(nitzSubs[4]);
   1340             c.set(Calendar.MINUTE, minute);
   1341 
   1342             int second = Integer.parseInt(nitzSubs[5]);
   1343             c.set(Calendar.SECOND, second);
   1344 
   1345             boolean sign = (nitz.indexOf('-') == -1);
   1346 
   1347             int tzOffset = Integer.parseInt(nitzSubs[6]);
   1348 
   1349             int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
   1350                                               : 0;
   1351 
   1352             // The zone offset received from NITZ is for current local time,
   1353             // so DST correction is already applied.  Don't add it again.
   1354             //
   1355             // tzOffset += dst * 4;
   1356             //
   1357             // We could unapply it if we wanted the raw offset.
   1358 
   1359             tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
   1360 
   1361             TimeZone    zone = null;
   1362 
   1363             // As a special extension, the Android emulator appends the name of
   1364             // the host computer's timezone to the nitz string. this is zoneinfo
   1365             // timezone name of the form Area!Location or Area!Location!SubLocation
   1366             // so we need to convert the ! into /
   1367             if (nitzSubs.length >= 9) {
   1368                 String  tzname = nitzSubs[8].replace('!','/');
   1369                 zone = TimeZone.getTimeZone( tzname );
   1370             }
   1371 
   1372             String iso = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
   1373 
   1374             if (zone == null) {
   1375                 if (mGotCountryCode) {
   1376                     if (iso != null && iso.length() > 0) {
   1377                         zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
   1378                                 c.getTimeInMillis(),
   1379                                 iso);
   1380                     } else {
   1381                         // We don't have a valid iso country code.  This is
   1382                         // most likely because we're on a test network that's
   1383                         // using a bogus MCC (eg, "001"), so get a TimeZone
   1384                         // based only on the NITZ parameters.
   1385                         zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
   1386                     }
   1387                 }
   1388             }
   1389 
   1390             if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){
   1391                 // We got the time before the country or the zone has changed
   1392                 // so we don't know how to identify the DST rules yet.  Save
   1393                 // the information and hope to fix it up later.
   1394 
   1395                 mNeedFixZone = true;
   1396                 mZoneOffset  = tzOffset;
   1397                 mZoneDst     = dst != 0;
   1398                 mZoneTime    = c.getTimeInMillis();
   1399             }
   1400             if (DBG) {
   1401                 log("NITZ: tzOffset=" + tzOffset + " dst=" + dst + " zone=" +
   1402                         (zone!=null ? zone.getID() : "NULL") +
   1403                         " iso=" + iso + " mGotCountryCode=" + mGotCountryCode +
   1404                         " mNeedFixZone=" + mNeedFixZone);
   1405             }
   1406 
   1407             if (zone != null) {
   1408                 if (getAutoTimeZone()) {
   1409                     setAndBroadcastNetworkSetTimeZone(zone.getID());
   1410                 }
   1411                 saveNitzTimeZone(zone.getID());
   1412             }
   1413 
   1414             String ignore = SystemProperties.get("gsm.ignore-nitz");
   1415             if (ignore != null && ignore.equals("yes")) {
   1416                 if (DBG) log("NITZ: Not setting clock because gsm.ignore-nitz is set");
   1417                 return;
   1418             }
   1419 
   1420             try {
   1421                 mWakeLock.acquire();
   1422 
   1423                 /**
   1424                  * Correct the NITZ time by how long its taken to get here.
   1425                  */
   1426                 long millisSinceNitzReceived
   1427                         = SystemClock.elapsedRealtime() - nitzReceiveTime;
   1428 
   1429                 if (millisSinceNitzReceived < 0) {
   1430                     // Sanity check: something is wrong
   1431                     if (DBG) {
   1432                         log("NITZ: not setting time, clock has rolled "
   1433                                         + "backwards since NITZ time was received, "
   1434                                         + nitz);
   1435                     }
   1436                     return;
   1437                 }
   1438 
   1439                 if (millisSinceNitzReceived > Integer.MAX_VALUE) {
   1440                     // If the time is this far off, something is wrong > 24 days!
   1441                     if (DBG) {
   1442                         log("NITZ: not setting time, processing has taken "
   1443                                     + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
   1444                                     + " days");
   1445                     }
   1446                     return;
   1447                 }
   1448 
   1449                 // Note: with range checks above, cast to int is safe
   1450                 c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
   1451 
   1452                 if (getAutoTime()) {
   1453                     /**
   1454                      * Update system time automatically
   1455                      */
   1456                     long gained = c.getTimeInMillis() - System.currentTimeMillis();
   1457                     long timeSinceLastUpdate = SystemClock.elapsedRealtime() - mSavedAtTime;
   1458                     int nitzUpdateSpacing = Settings.Global.getInt(mCr,
   1459                             Settings.Global.NITZ_UPDATE_SPACING, mNitzUpdateSpacing);
   1460                     int nitzUpdateDiff = Settings.Global.getInt(mCr,
   1461                             Settings.Global.NITZ_UPDATE_DIFF, mNitzUpdateDiff);
   1462 
   1463                     if ((mSavedAtTime == 0) || (timeSinceLastUpdate > nitzUpdateSpacing)
   1464                             || (Math.abs(gained) > nitzUpdateDiff)) {
   1465                         if (DBG) {
   1466                             log("NITZ: Auto updating time of day to " + c.getTime()
   1467                                 + " NITZ receive delay=" + millisSinceNitzReceived
   1468                                 + "ms gained=" + gained + "ms from " + nitz);
   1469                         }
   1470 
   1471                         setAndBroadcastNetworkSetTime(c.getTimeInMillis());
   1472                     } else {
   1473                         if (DBG) {
   1474                             log("NITZ: ignore, a previous update was "
   1475                                 + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms");
   1476                         }
   1477                         return;
   1478                     }
   1479                 }
   1480 
   1481                 /**
   1482                  * Update properties and save the time we did the update
   1483                  */
   1484                 if (DBG) log("NITZ: update nitz time property");
   1485                 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
   1486                 mSavedTime = c.getTimeInMillis();
   1487                 mSavedAtTime = SystemClock.elapsedRealtime();
   1488             } finally {
   1489                 long end = SystemClock.elapsedRealtime();
   1490                 if (DBG) log("NITZ: end=" + end + " dur=" + (end - start));
   1491                 mWakeLock.release();
   1492             }
   1493         } catch (RuntimeException ex) {
   1494             loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
   1495         }
   1496     }
   1497 
   1498     private boolean getAutoTime() {
   1499         try {
   1500             return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME) > 0;
   1501         } catch (SettingNotFoundException snfe) {
   1502             return true;
   1503         }
   1504     }
   1505 
   1506     private boolean getAutoTimeZone() {
   1507         try {
   1508             return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE) > 0;
   1509         } catch (SettingNotFoundException snfe) {
   1510             return true;
   1511         }
   1512     }
   1513 
   1514     private void saveNitzTimeZone(String zoneId) {
   1515         mSavedTimeZone = zoneId;
   1516     }
   1517 
   1518     /**
   1519      * Set the timezone and send out a sticky broadcast so the system can
   1520      * determine if the timezone was set by the carrier.
   1521      *
   1522      * @param zoneId timezone set by carrier
   1523      */
   1524     private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
   1525         if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId);
   1526         AlarmManager alarm =
   1527             (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
   1528         alarm.setTimeZone(zoneId);
   1529         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
   1530         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1531         intent.putExtra("time-zone", zoneId);
   1532         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1533     }
   1534 
   1535     /**
   1536      * Set the time and Send out a sticky broadcast so the system can determine
   1537      * if the time was set by the carrier.
   1538      *
   1539      * @param time time set by network
   1540      */
   1541     private void setAndBroadcastNetworkSetTime(long time) {
   1542         if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
   1543         SystemClock.setCurrentTimeMillis(time);
   1544         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
   1545         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1546         intent.putExtra("time", time);
   1547         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1548     }
   1549 
   1550     private void revertToNitzTime() {
   1551         if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME, 0) == 0) {
   1552             return;
   1553         }
   1554         if (DBG) {
   1555             log("revertToNitzTime: mSavedTime=" + mSavedTime + " mSavedAtTime=" + mSavedAtTime);
   1556         }
   1557         if (mSavedTime != 0 && mSavedAtTime != 0) {
   1558             setAndBroadcastNetworkSetTime(mSavedTime
   1559                     + (SystemClock.elapsedRealtime() - mSavedAtTime));
   1560         }
   1561     }
   1562 
   1563     private void revertToNitzTimeZone() {
   1564         if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1565                 Settings.Global.AUTO_TIME_ZONE, 0) == 0) {
   1566             return;
   1567         }
   1568         if (DBG) log("revertToNitzTimeZone: tz='" + mSavedTimeZone);
   1569         if (mSavedTimeZone != null) {
   1570             setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
   1571         }
   1572     }
   1573 
   1574     protected boolean isSidsAllZeros() {
   1575         if (mHomeSystemId != null) {
   1576             for (int i=0; i < mHomeSystemId.length; i++) {
   1577                 if (mHomeSystemId[i] != 0) {
   1578                     return false;
   1579                 }
   1580             }
   1581         }
   1582         return true;
   1583     }
   1584 
   1585     /**
   1586      * Check whether a specified system ID that matches one of the home system IDs.
   1587      */
   1588     private boolean isHomeSid(int sid) {
   1589         if (mHomeSystemId != null) {
   1590             for (int i=0; i < mHomeSystemId.length; i++) {
   1591                 if (sid == mHomeSystemId[i]) {
   1592                     return true;
   1593                 }
   1594             }
   1595         }
   1596         return false;
   1597     }
   1598 
   1599     /**
   1600      * @return true if phone is camping on a technology
   1601      * that could support voice and data simultaneously.
   1602      */
   1603     @Override
   1604     public boolean isConcurrentVoiceAndDataAllowed() {
   1605         // Note: it needs to be confirmed which CDMA network types
   1606         // can support voice and data calls concurrently.
   1607         // For the time-being, the return value will be false.
   1608         return false;
   1609     }
   1610 
   1611     public String getMdnNumber() {
   1612         return mMdn;
   1613     }
   1614 
   1615     public String getCdmaMin() {
   1616          return mMin;
   1617     }
   1618 
   1619     /** Returns null if NV is not yet ready */
   1620     public String getPrlVersion() {
   1621         return mPrlVersion;
   1622     }
   1623 
   1624     /**
   1625      * Returns IMSI as MCC + MNC + MIN
   1626      */
   1627     String getImsi() {
   1628         // TODO: When RUIM is enabled, IMSI will come from RUIM not build-time props.
   1629         String operatorNumeric = SystemProperties.get(
   1630                 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
   1631 
   1632         if (!TextUtils.isEmpty(operatorNumeric) && getCdmaMin() != null) {
   1633             return (operatorNumeric + getCdmaMin());
   1634         } else {
   1635             return null;
   1636         }
   1637     }
   1638 
   1639     /**
   1640      * Check if subscription data has been assigned to mMin
   1641      *
   1642      * return true if MIN info is ready; false otherwise.
   1643      */
   1644     public boolean isMinInfoReady() {
   1645         return mIsMinInfoReady;
   1646     }
   1647 
   1648     /**
   1649      * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED
   1650      */
   1651     int getOtasp() {
   1652         int provisioningState;
   1653         if (mMin == null || (mMin.length() < 6)) {
   1654             if (DBG) log("getOtasp: bad mMin='" + mMin + "'");
   1655             provisioningState = OTASP_UNKNOWN;
   1656         } else {
   1657             if ((mMin.equals(UNACTIVATED_MIN_VALUE)
   1658                     || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
   1659                     || SystemProperties.getBoolean("test_cdma_setup", false)) {
   1660                 provisioningState = OTASP_NEEDED;
   1661             } else {
   1662                 provisioningState = OTASP_NOT_NEEDED;
   1663             }
   1664         }
   1665         if (DBG) log("getOtasp: state=" + provisioningState);
   1666         return provisioningState;
   1667     }
   1668 
   1669     @Override
   1670     protected void hangupAndPowerOff() {
   1671         // hang up all active voice calls
   1672         mPhone.mCT.mRingingCall.hangupIfAlive();
   1673         mPhone.mCT.mBackgroundCall.hangupIfAlive();
   1674         mPhone.mCT.mForegroundCall.hangupIfAlive();
   1675         mCi.setRadioPower(false, null);
   1676     }
   1677 
   1678     protected void parseSidNid (String sidStr, String nidStr) {
   1679         if (sidStr != null) {
   1680             String[] sid = sidStr.split(",");
   1681             mHomeSystemId = new int[sid.length];
   1682             for (int i = 0; i < sid.length; i++) {
   1683                 try {
   1684                     mHomeSystemId[i] = Integer.parseInt(sid[i]);
   1685                 } catch (NumberFormatException ex) {
   1686                     loge("error parsing system id: " + ex);
   1687                 }
   1688             }
   1689         }
   1690         if (DBG) log("CDMA_SUBSCRIPTION: SID=" + sidStr);
   1691 
   1692         if (nidStr != null) {
   1693             String[] nid = nidStr.split(",");
   1694             mHomeNetworkId = new int[nid.length];
   1695             for (int i = 0; i < nid.length; i++) {
   1696                 try {
   1697                     mHomeNetworkId[i] = Integer.parseInt(nid[i]);
   1698                 } catch (NumberFormatException ex) {
   1699                     loge("CDMA_SUBSCRIPTION: error parsing network id: " + ex);
   1700                 }
   1701             }
   1702         }
   1703         if (DBG) log("CDMA_SUBSCRIPTION: NID=" + nidStr);
   1704     }
   1705 
   1706     protected void updateOtaspState() {
   1707         int otaspMode = getOtasp();
   1708         int oldOtaspMode = mCurrentOtaspMode;
   1709         mCurrentOtaspMode = otaspMode;
   1710 
   1711         // Notify apps subscription info is ready
   1712         if (mCdmaForSubscriptionInfoReadyRegistrants != null) {
   1713             if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()");
   1714             mCdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
   1715         }
   1716         if (oldOtaspMode != mCurrentOtaspMode) {
   1717             if (DBG) {
   1718                 log("CDMA_SUBSCRIPTION: call notifyOtaspChanged old otaspMode=" +
   1719                     oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode);
   1720             }
   1721             mPhone.notifyOtaspChanged(mCurrentOtaspMode);
   1722         }
   1723     }
   1724 
   1725     @Override
   1726     protected void onUpdateIccAvailability() {
   1727         if (mUiccController == null ) {
   1728             return;
   1729         }
   1730 
   1731         UiccCardApplication newUiccApplication =
   1732                 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP2);
   1733 
   1734         if (mUiccApplcation != newUiccApplication) {
   1735             if (mUiccApplcation != null) {
   1736                 log("Removing stale icc objects.");
   1737                 mUiccApplcation.unregisterForReady(this);
   1738                 if (mIccRecords != null) {
   1739                     mIccRecords.unregisterForRecordsLoaded(this);
   1740                 }
   1741                 mIccRecords = null;
   1742                 mUiccApplcation = null;
   1743             }
   1744             if (newUiccApplication != null) {
   1745                 log("New card found");
   1746                 mUiccApplcation = newUiccApplication;
   1747                 mIccRecords = mUiccApplcation.getIccRecords();
   1748                 if (mIsSubscriptionFromRuim) {
   1749                     mUiccApplcation.registerForReady(this, EVENT_RUIM_READY, null);
   1750                     if (mIccRecords != null) {
   1751                         mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
   1752                     }
   1753                 }
   1754             }
   1755         }
   1756     }
   1757 
   1758     @Override
   1759     protected void log(String s) {
   1760         Rlog.d(LOG_TAG, "[CdmaSST] " + s);
   1761     }
   1762 
   1763     @Override
   1764     protected void loge(String s) {
   1765         Rlog.e(LOG_TAG, "[CdmaSST] " + s);
   1766     }
   1767 
   1768     @Override
   1769     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1770         pw.println("CdmaServiceStateTracker extends:");
   1771         super.dump(fd, pw, args);
   1772         pw.println(" mPhone=" + mPhone);
   1773         pw.println(" mSS=" + mSS);
   1774         pw.println(" mNewSS=" + mNewSS);
   1775         pw.println(" mCellLoc=" + mCellLoc);
   1776         pw.println(" mNewCellLoc=" + mNewCellLoc);
   1777         pw.println(" mCurrentOtaspMode=" + mCurrentOtaspMode);
   1778         pw.println(" mCdmaRoaming=" + mCdmaRoaming);
   1779         pw.println(" mRoamingIndicator=" + mRoamingIndicator);
   1780         pw.println(" mIsInPrl=" + mIsInPrl);
   1781         pw.println(" mDefaultRoamingIndicator=" + mDefaultRoamingIndicator);
   1782         pw.println(" mRegistrationState=" + mRegistrationState);
   1783         pw.println(" mNeedFixZone=" + mNeedFixZone);
   1784         pw.println(" mZoneOffset=" + mZoneOffset);
   1785         pw.println(" mZoneDst=" + mZoneDst);
   1786         pw.println(" mZoneTime=" + mZoneTime);
   1787         pw.println(" mGotCountryCode=" + mGotCountryCode);
   1788         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
   1789         pw.println(" mSavedTime=" + mSavedTime);
   1790         pw.println(" mSavedAtTime=" + mSavedAtTime);
   1791         pw.println(" mWakeLock=" + mWakeLock);
   1792         pw.println(" mCurPlmn=" + mCurPlmn);
   1793         pw.println(" mMdn=" + mMdn);
   1794         pw.println(" mHomeSystemId=" + mHomeSystemId);
   1795         pw.println(" mHomeNetworkId=" + mHomeNetworkId);
   1796         pw.println(" mMin=" + mMin);
   1797         pw.println(" mPrlVersion=" + mPrlVersion);
   1798         pw.println(" mIsMinInfoReady=" + mIsMinInfoReady);
   1799         pw.println(" mIsEriTextLoaded=" + mIsEriTextLoaded);
   1800         pw.println(" mIsSubscriptionFromRuim=" + mIsSubscriptionFromRuim);
   1801         pw.println(" mCdmaSSM=" + mCdmaSSM);
   1802         pw.println(" mRegistrationDeniedReason=" + mRegistrationDeniedReason);
   1803         pw.println(" mCurrentCarrier=" + mCurrentCarrier);
   1804     }
   1805 }
   1806