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 
   1074             if (operatorNumeric == null) {
   1075                 if (DBG) log("operatorNumeric is null");
   1076                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
   1077                 mGotCountryCode = false;
   1078             } else {
   1079                 String isoCountryCode = "";
   1080                 String mcc = operatorNumeric.substring(0, 3);
   1081                 try{
   1082                     isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(
   1083                             operatorNumeric.substring(0,3)));
   1084                 } catch ( NumberFormatException ex){
   1085                     loge("pollStateDone: countryCodeForMcc error" + ex);
   1086                 } catch ( StringIndexOutOfBoundsException ex) {
   1087                     loge("pollStateDone: countryCodeForMcc error" + ex);
   1088                 }
   1089 
   1090                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
   1091                         isoCountryCode);
   1092                 mGotCountryCode = true;
   1093 
   1094                 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
   1095                         mNeedFixZone)) {
   1096                     fixTimeZone(isoCountryCode);
   1097                 }
   1098             }
   1099 
   1100             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
   1101                     mSS.getRoaming() ? "true" : "false");
   1102 
   1103             updateSpnDisplay();
   1104             mPhone.notifyServiceStateChanged(mSS);
   1105         }
   1106 
   1107         if (hasCdmaDataConnectionAttached) {
   1108             mAttachedRegistrants.notifyRegistrants();
   1109         }
   1110 
   1111         if (hasCdmaDataConnectionDetached) {
   1112             mDetachedRegistrants.notifyRegistrants();
   1113         }
   1114 
   1115         if (hasCdmaDataConnectionChanged || hasRilDataRadioTechnologyChanged) {
   1116             notifyDataRegStateRilRadioTechnologyChanged();
   1117             mPhone.notifyDataConnection(null);
   1118         }
   1119 
   1120         if (hasRoamingOn) {
   1121             mRoamingOnRegistrants.notifyRegistrants();
   1122         }
   1123 
   1124         if (hasRoamingOff) {
   1125             mRoamingOffRegistrants.notifyRegistrants();
   1126         }
   1127 
   1128         if (hasLocationChanged) {
   1129             mPhone.notifyLocationChanged();
   1130         }
   1131         // TODO: Add CdmaCellIdenity updating, see CdmaLteServiceStateTracker.
   1132     }
   1133 
   1134     /**
   1135      * Returns a TimeZone object based only on parameters from the NITZ string.
   1136      */
   1137     private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
   1138         TimeZone guess = findTimeZone(offset, dst, when);
   1139         if (guess == null) {
   1140             // Couldn't find a proper timezone.  Perhaps the DST data is wrong.
   1141             guess = findTimeZone(offset, !dst, when);
   1142         }
   1143         if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID()));
   1144         return guess;
   1145     }
   1146 
   1147     private TimeZone findTimeZone(int offset, boolean dst, long when) {
   1148         int rawOffset = offset;
   1149         if (dst) {
   1150             rawOffset -= 3600000;
   1151         }
   1152         String[] zones = TimeZone.getAvailableIDs(rawOffset);
   1153         TimeZone guess = null;
   1154         Date d = new Date(when);
   1155         for (String zone : zones) {
   1156             TimeZone tz = TimeZone.getTimeZone(zone);
   1157             if (tz.getOffset(when) == offset &&
   1158                     tz.inDaylightTime(d) == dst) {
   1159                 guess = tz;
   1160                 break;
   1161             }
   1162         }
   1163 
   1164         return guess;
   1165     }
   1166 
   1167     /**
   1168      * TODO: This code is exactly the same as in GsmServiceStateTracker
   1169      * and has a TODO to not poll signal strength if screen is off.
   1170      * This code should probably be hoisted to the base class so
   1171      * the fix, when added, works for both.
   1172      */
   1173     private void
   1174     queueNextSignalStrengthPoll() {
   1175         if (mDontPollSignalStrength) {
   1176             // The radio is telling us about signal strength changes
   1177             // we don't have to ask it
   1178             return;
   1179         }
   1180 
   1181         Message msg;
   1182 
   1183         msg = obtainMessage();
   1184         msg.what = EVENT_POLL_SIGNAL_STRENGTH;
   1185 
   1186         // TODO Don't poll signal strength if screen is off
   1187         sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
   1188     }
   1189 
   1190     protected int radioTechnologyToDataServiceState(int code) {
   1191         int retVal = ServiceState.STATE_OUT_OF_SERVICE;
   1192         switch(code) {
   1193         case 0:
   1194         case 1:
   1195         case 2:
   1196         case 3:
   1197         case 4:
   1198         case 5:
   1199             break;
   1200         case 6: // RADIO_TECHNOLOGY_1xRTT
   1201         case 7: // RADIO_TECHNOLOGY_EVDO_0
   1202         case 8: // RADIO_TECHNOLOGY_EVDO_A
   1203         case 12: // RADIO_TECHNOLOGY_EVDO_B
   1204         case 13: // RADIO_TECHNOLOGY_EHRPD
   1205             retVal = ServiceState.STATE_IN_SERVICE;
   1206             break;
   1207         default:
   1208             loge("radioTechnologyToDataServiceState: Wrong radioTechnology code.");
   1209         break;
   1210         }
   1211         return(retVal);
   1212     }
   1213 
   1214     /** code is registration state 0-5 from TS 27.007 7.2 */
   1215     protected int
   1216     regCodeToServiceState(int code) {
   1217         switch (code) {
   1218         case 0: // Not searching and not registered
   1219             return ServiceState.STATE_OUT_OF_SERVICE;
   1220         case 1:
   1221             return ServiceState.STATE_IN_SERVICE;
   1222         case 2: // 2 is "searching", fall through
   1223         case 3: // 3 is "registration denied", fall through
   1224         case 4: // 4 is "unknown", not valid in current baseband
   1225             return ServiceState.STATE_OUT_OF_SERVICE;
   1226         case 5:// 5 is "Registered, roaming"
   1227             return ServiceState.STATE_IN_SERVICE;
   1228 
   1229         default:
   1230             loge("regCodeToServiceState: unexpected service state " + code);
   1231         return ServiceState.STATE_OUT_OF_SERVICE;
   1232         }
   1233     }
   1234 
   1235     @Override
   1236     public int getCurrentDataConnectionState() {
   1237         return mSS.getDataRegState();
   1238     }
   1239 
   1240     /**
   1241      * code is registration state 0-5 from TS 27.007 7.2
   1242      * returns true if registered roam, false otherwise
   1243      */
   1244     private boolean
   1245     regCodeIsRoaming (int code) {
   1246         // 5 is  "in service -- roam"
   1247         return 5 == code;
   1248     }
   1249 
   1250     /**
   1251      * Determine whether a roaming indicator is in the carrier-specified list of ERIs for
   1252      * home system
   1253      *
   1254      * @param roamInd roaming indicator in String
   1255      * @return true if the roamInd is in the carrier-specified list of ERIs for home network
   1256      */
   1257     private boolean isRoamIndForHomeSystem(String roamInd) {
   1258         // retrieve the carrier-specified list of ERIs for home system
   1259         String homeRoamIndicators = SystemProperties.get("ro.cdma.homesystem");
   1260 
   1261         if (!TextUtils.isEmpty(homeRoamIndicators)) {
   1262             // searches through the comma-separated list for a match,
   1263             // return true if one is found.
   1264             for (String homeRoamInd : homeRoamIndicators.split(",")) {
   1265                 if (homeRoamInd.equals(roamInd)) {
   1266                     return true;
   1267                 }
   1268             }
   1269             // no matches found against the list!
   1270             return false;
   1271         }
   1272 
   1273         // no system property found for the roaming indicators for home system
   1274         return false;
   1275     }
   1276 
   1277     /**
   1278      * Set roaming state when cdmaRoaming is true and ons is different from spn
   1279      * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming
   1280      * @param s ServiceState hold current ons
   1281      * @return true for roaming state set
   1282      */
   1283     private
   1284     boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) {
   1285         String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty");
   1286 
   1287         // NOTE: in case of RUIM we should completely ignore the ERI data file and
   1288         // mOperatorAlphaLong is set from RIL_REQUEST_OPERATOR response 0 (alpha ONS)
   1289         String onsl = s.getOperatorAlphaLong();
   1290         String onss = s.getOperatorAlphaShort();
   1291 
   1292         boolean equalsOnsl = onsl != null && spn.equals(onsl);
   1293         boolean equalsOnss = onss != null && spn.equals(onss);
   1294 
   1295         return cdmaRoaming && !(equalsOnsl || equalsOnss);
   1296     }
   1297 
   1298 
   1299     /**
   1300      * nitzReceiveTime is time_t that the NITZ time was posted
   1301      */
   1302 
   1303     private
   1304     void setTimeFromNITZString (String nitz, long nitzReceiveTime)
   1305     {
   1306         // "yy/mm/dd,hh:mm:ss(+/-)tz"
   1307         // tz is in number of quarter-hours
   1308 
   1309         long start = SystemClock.elapsedRealtime();
   1310         if (DBG) {
   1311             log("NITZ: " + nitz + "," + nitzReceiveTime +
   1312                         " start=" + start + " delay=" + (start - nitzReceiveTime));
   1313         }
   1314 
   1315         try {
   1316             /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
   1317              * offset as well (which we won't worry about until later) */
   1318             Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
   1319 
   1320             c.clear();
   1321             c.set(Calendar.DST_OFFSET, 0);
   1322 
   1323             String[] nitzSubs = nitz.split("[/:,+-]");
   1324 
   1325             int year = 2000 + Integer.parseInt(nitzSubs[0]);
   1326             c.set(Calendar.YEAR, year);
   1327 
   1328             // month is 0 based!
   1329             int month = Integer.parseInt(nitzSubs[1]) - 1;
   1330             c.set(Calendar.MONTH, month);
   1331 
   1332             int date = Integer.parseInt(nitzSubs[2]);
   1333             c.set(Calendar.DATE, date);
   1334 
   1335             int hour = Integer.parseInt(nitzSubs[3]);
   1336             c.set(Calendar.HOUR, hour);
   1337 
   1338             int minute = Integer.parseInt(nitzSubs[4]);
   1339             c.set(Calendar.MINUTE, minute);
   1340 
   1341             int second = Integer.parseInt(nitzSubs[5]);
   1342             c.set(Calendar.SECOND, second);
   1343 
   1344             boolean sign = (nitz.indexOf('-') == -1);
   1345 
   1346             int tzOffset = Integer.parseInt(nitzSubs[6]);
   1347 
   1348             int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
   1349                                               : 0;
   1350 
   1351             // The zone offset received from NITZ is for current local time,
   1352             // so DST correction is already applied.  Don't add it again.
   1353             //
   1354             // tzOffset += dst * 4;
   1355             //
   1356             // We could unapply it if we wanted the raw offset.
   1357 
   1358             tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
   1359 
   1360             TimeZone    zone = null;
   1361 
   1362             // As a special extension, the Android emulator appends the name of
   1363             // the host computer's timezone to the nitz string. this is zoneinfo
   1364             // timezone name of the form Area!Location or Area!Location!SubLocation
   1365             // so we need to convert the ! into /
   1366             if (nitzSubs.length >= 9) {
   1367                 String  tzname = nitzSubs[8].replace('!','/');
   1368                 zone = TimeZone.getTimeZone( tzname );
   1369             }
   1370 
   1371             String iso = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
   1372 
   1373             if (zone == null) {
   1374                 if (mGotCountryCode) {
   1375                     if (iso != null && iso.length() > 0) {
   1376                         zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
   1377                                 c.getTimeInMillis(),
   1378                                 iso);
   1379                     } else {
   1380                         // We don't have a valid iso country code.  This is
   1381                         // most likely because we're on a test network that's
   1382                         // using a bogus MCC (eg, "001"), so get a TimeZone
   1383                         // based only on the NITZ parameters.
   1384                         zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
   1385                     }
   1386                 }
   1387             }
   1388 
   1389             if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){
   1390                 // We got the time before the country or the zone has changed
   1391                 // so we don't know how to identify the DST rules yet.  Save
   1392                 // the information and hope to fix it up later.
   1393 
   1394                 mNeedFixZone = true;
   1395                 mZoneOffset  = tzOffset;
   1396                 mZoneDst     = dst != 0;
   1397                 mZoneTime    = c.getTimeInMillis();
   1398             }
   1399             if (DBG) {
   1400                 log("NITZ: tzOffset=" + tzOffset + " dst=" + dst + " zone=" +
   1401                         (zone!=null ? zone.getID() : "NULL") +
   1402                         " iso=" + iso + " mGotCountryCode=" + mGotCountryCode +
   1403                         " mNeedFixZone=" + mNeedFixZone);
   1404             }
   1405 
   1406             if (zone != null) {
   1407                 if (getAutoTimeZone()) {
   1408                     setAndBroadcastNetworkSetTimeZone(zone.getID());
   1409                 }
   1410                 saveNitzTimeZone(zone.getID());
   1411             }
   1412 
   1413             String ignore = SystemProperties.get("gsm.ignore-nitz");
   1414             if (ignore != null && ignore.equals("yes")) {
   1415                 if (DBG) log("NITZ: Not setting clock because gsm.ignore-nitz is set");
   1416                 return;
   1417             }
   1418 
   1419             try {
   1420                 mWakeLock.acquire();
   1421 
   1422                 /**
   1423                  * Correct the NITZ time by how long its taken to get here.
   1424                  */
   1425                 long millisSinceNitzReceived
   1426                         = SystemClock.elapsedRealtime() - nitzReceiveTime;
   1427 
   1428                 if (millisSinceNitzReceived < 0) {
   1429                     // Sanity check: something is wrong
   1430                     if (DBG) {
   1431                         log("NITZ: not setting time, clock has rolled "
   1432                                         + "backwards since NITZ time was received, "
   1433                                         + nitz);
   1434                     }
   1435                     return;
   1436                 }
   1437 
   1438                 if (millisSinceNitzReceived > Integer.MAX_VALUE) {
   1439                     // If the time is this far off, something is wrong > 24 days!
   1440                     if (DBG) {
   1441                         log("NITZ: not setting time, processing has taken "
   1442                                     + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
   1443                                     + " days");
   1444                     }
   1445                     return;
   1446                 }
   1447 
   1448                 // Note: with range checks above, cast to int is safe
   1449                 c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
   1450 
   1451                 if (getAutoTime()) {
   1452                     /**
   1453                      * Update system time automatically
   1454                      */
   1455                     long gained = c.getTimeInMillis() - System.currentTimeMillis();
   1456                     long timeSinceLastUpdate = SystemClock.elapsedRealtime() - mSavedAtTime;
   1457                     int nitzUpdateSpacing = Settings.Global.getInt(mCr,
   1458                             Settings.Global.NITZ_UPDATE_SPACING, mNitzUpdateSpacing);
   1459                     int nitzUpdateDiff = Settings.Global.getInt(mCr,
   1460                             Settings.Global.NITZ_UPDATE_DIFF, mNitzUpdateDiff);
   1461 
   1462                     if ((mSavedAtTime == 0) || (timeSinceLastUpdate > nitzUpdateSpacing)
   1463                             || (Math.abs(gained) > nitzUpdateDiff)) {
   1464                         if (DBG) {
   1465                             log("NITZ: Auto updating time of day to " + c.getTime()
   1466                                 + " NITZ receive delay=" + millisSinceNitzReceived
   1467                                 + "ms gained=" + gained + "ms from " + nitz);
   1468                         }
   1469 
   1470                         setAndBroadcastNetworkSetTime(c.getTimeInMillis());
   1471                     } else {
   1472                         if (DBG) {
   1473                             log("NITZ: ignore, a previous update was "
   1474                                 + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms");
   1475                         }
   1476                         return;
   1477                     }
   1478                 }
   1479 
   1480                 /**
   1481                  * Update properties and save the time we did the update
   1482                  */
   1483                 if (DBG) log("NITZ: update nitz time property");
   1484                 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
   1485                 mSavedTime = c.getTimeInMillis();
   1486                 mSavedAtTime = SystemClock.elapsedRealtime();
   1487             } finally {
   1488                 long end = SystemClock.elapsedRealtime();
   1489                 if (DBG) log("NITZ: end=" + end + " dur=" + (end - start));
   1490                 mWakeLock.release();
   1491             }
   1492         } catch (RuntimeException ex) {
   1493             loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
   1494         }
   1495     }
   1496 
   1497     private boolean getAutoTime() {
   1498         try {
   1499             return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME) > 0;
   1500         } catch (SettingNotFoundException snfe) {
   1501             return true;
   1502         }
   1503     }
   1504 
   1505     private boolean getAutoTimeZone() {
   1506         try {
   1507             return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE) > 0;
   1508         } catch (SettingNotFoundException snfe) {
   1509             return true;
   1510         }
   1511     }
   1512 
   1513     private void saveNitzTimeZone(String zoneId) {
   1514         mSavedTimeZone = zoneId;
   1515     }
   1516 
   1517     /**
   1518      * Set the timezone and send out a sticky broadcast so the system can
   1519      * determine if the timezone was set by the carrier.
   1520      *
   1521      * @param zoneId timezone set by carrier
   1522      */
   1523     private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
   1524         if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId);
   1525         AlarmManager alarm =
   1526             (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
   1527         alarm.setTimeZone(zoneId);
   1528         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
   1529         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1530         intent.putExtra("time-zone", zoneId);
   1531         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1532     }
   1533 
   1534     /**
   1535      * Set the time and Send out a sticky broadcast so the system can determine
   1536      * if the time was set by the carrier.
   1537      *
   1538      * @param time time set by network
   1539      */
   1540     private void setAndBroadcastNetworkSetTime(long time) {
   1541         if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
   1542         SystemClock.setCurrentTimeMillis(time);
   1543         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
   1544         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1545         intent.putExtra("time", time);
   1546         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1547     }
   1548 
   1549     private void revertToNitzTime() {
   1550         if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME, 0) == 0) {
   1551             return;
   1552         }
   1553         if (DBG) {
   1554             log("revertToNitzTime: mSavedTime=" + mSavedTime + " mSavedAtTime=" + mSavedAtTime);
   1555         }
   1556         if (mSavedTime != 0 && mSavedAtTime != 0) {
   1557             setAndBroadcastNetworkSetTime(mSavedTime
   1558                     + (SystemClock.elapsedRealtime() - mSavedAtTime));
   1559         }
   1560     }
   1561 
   1562     private void revertToNitzTimeZone() {
   1563         if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1564                 Settings.Global.AUTO_TIME_ZONE, 0) == 0) {
   1565             return;
   1566         }
   1567         if (DBG) log("revertToNitzTimeZone: tz='" + mSavedTimeZone);
   1568         if (mSavedTimeZone != null) {
   1569             setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
   1570         }
   1571     }
   1572 
   1573     protected boolean isSidsAllZeros() {
   1574         if (mHomeSystemId != null) {
   1575             for (int i=0; i < mHomeSystemId.length; i++) {
   1576                 if (mHomeSystemId[i] != 0) {
   1577                     return false;
   1578                 }
   1579             }
   1580         }
   1581         return true;
   1582     }
   1583 
   1584     /**
   1585      * Check whether a specified system ID that matches one of the home system IDs.
   1586      */
   1587     private boolean isHomeSid(int sid) {
   1588         if (mHomeSystemId != null) {
   1589             for (int i=0; i < mHomeSystemId.length; i++) {
   1590                 if (sid == mHomeSystemId[i]) {
   1591                     return true;
   1592                 }
   1593             }
   1594         }
   1595         return false;
   1596     }
   1597 
   1598     /**
   1599      * @return true if phone is camping on a technology
   1600      * that could support voice and data simultaneously.
   1601      */
   1602     @Override
   1603     public boolean isConcurrentVoiceAndDataAllowed() {
   1604         // Note: it needs to be confirmed which CDMA network types
   1605         // can support voice and data calls concurrently.
   1606         // For the time-being, the return value will be false.
   1607         return false;
   1608     }
   1609 
   1610     public String getMdnNumber() {
   1611         return mMdn;
   1612     }
   1613 
   1614     public String getCdmaMin() {
   1615          return mMin;
   1616     }
   1617 
   1618     /** Returns null if NV is not yet ready */
   1619     public String getPrlVersion() {
   1620         return mPrlVersion;
   1621     }
   1622 
   1623     /**
   1624      * Returns IMSI as MCC + MNC + MIN
   1625      */
   1626     String getImsi() {
   1627         // TODO: When RUIM is enabled, IMSI will come from RUIM not build-time props.
   1628         String operatorNumeric = SystemProperties.get(
   1629                 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
   1630 
   1631         if (!TextUtils.isEmpty(operatorNumeric) && getCdmaMin() != null) {
   1632             return (operatorNumeric + getCdmaMin());
   1633         } else {
   1634             return null;
   1635         }
   1636     }
   1637 
   1638     /**
   1639      * Check if subscription data has been assigned to mMin
   1640      *
   1641      * return true if MIN info is ready; false otherwise.
   1642      */
   1643     public boolean isMinInfoReady() {
   1644         return mIsMinInfoReady;
   1645     }
   1646 
   1647     /**
   1648      * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED
   1649      */
   1650     int getOtasp() {
   1651         int provisioningState;
   1652         if (mMin == null || (mMin.length() < 6)) {
   1653             if (DBG) log("getOtasp: bad mMin='" + mMin + "'");
   1654             provisioningState = OTASP_UNKNOWN;
   1655         } else {
   1656             if ((mMin.equals(UNACTIVATED_MIN_VALUE)
   1657                     || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
   1658                     || SystemProperties.getBoolean("test_cdma_setup", false)) {
   1659                 provisioningState = OTASP_NEEDED;
   1660             } else {
   1661                 provisioningState = OTASP_NOT_NEEDED;
   1662             }
   1663         }
   1664         if (DBG) log("getOtasp: state=" + provisioningState);
   1665         return provisioningState;
   1666     }
   1667 
   1668     @Override
   1669     protected void hangupAndPowerOff() {
   1670         // hang up all active voice calls
   1671         mPhone.mCT.mRingingCall.hangupIfAlive();
   1672         mPhone.mCT.mBackgroundCall.hangupIfAlive();
   1673         mPhone.mCT.mForegroundCall.hangupIfAlive();
   1674         mCi.setRadioPower(false, null);
   1675     }
   1676 
   1677     protected void parseSidNid (String sidStr, String nidStr) {
   1678         if (sidStr != null) {
   1679             String[] sid = sidStr.split(",");
   1680             mHomeSystemId = new int[sid.length];
   1681             for (int i = 0; i < sid.length; i++) {
   1682                 try {
   1683                     mHomeSystemId[i] = Integer.parseInt(sid[i]);
   1684                 } catch (NumberFormatException ex) {
   1685                     loge("error parsing system id: " + ex);
   1686                 }
   1687             }
   1688         }
   1689         if (DBG) log("CDMA_SUBSCRIPTION: SID=" + sidStr);
   1690 
   1691         if (nidStr != null) {
   1692             String[] nid = nidStr.split(",");
   1693             mHomeNetworkId = new int[nid.length];
   1694             for (int i = 0; i < nid.length; i++) {
   1695                 try {
   1696                     mHomeNetworkId[i] = Integer.parseInt(nid[i]);
   1697                 } catch (NumberFormatException ex) {
   1698                     loge("CDMA_SUBSCRIPTION: error parsing network id: " + ex);
   1699                 }
   1700             }
   1701         }
   1702         if (DBG) log("CDMA_SUBSCRIPTION: NID=" + nidStr);
   1703     }
   1704 
   1705     protected void updateOtaspState() {
   1706         int otaspMode = getOtasp();
   1707         int oldOtaspMode = mCurrentOtaspMode;
   1708         mCurrentOtaspMode = otaspMode;
   1709 
   1710         // Notify apps subscription info is ready
   1711         if (mCdmaForSubscriptionInfoReadyRegistrants != null) {
   1712             if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()");
   1713             mCdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
   1714         }
   1715         if (oldOtaspMode != mCurrentOtaspMode) {
   1716             if (DBG) {
   1717                 log("CDMA_SUBSCRIPTION: call notifyOtaspChanged old otaspMode=" +
   1718                     oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode);
   1719             }
   1720             mPhone.notifyOtaspChanged(mCurrentOtaspMode);
   1721         }
   1722     }
   1723 
   1724     @Override
   1725     protected void onUpdateIccAvailability() {
   1726         if (mUiccController == null ) {
   1727             return;
   1728         }
   1729 
   1730         UiccCardApplication newUiccApplication =
   1731                 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP2);
   1732 
   1733         if (mUiccApplcation != newUiccApplication) {
   1734             if (mUiccApplcation != null) {
   1735                 log("Removing stale icc objects.");
   1736                 mUiccApplcation.unregisterForReady(this);
   1737                 if (mIccRecords != null) {
   1738                     mIccRecords.unregisterForRecordsLoaded(this);
   1739                 }
   1740                 mIccRecords = null;
   1741                 mUiccApplcation = null;
   1742             }
   1743             if (newUiccApplication != null) {
   1744                 log("New card found");
   1745                 mUiccApplcation = newUiccApplication;
   1746                 mIccRecords = mUiccApplcation.getIccRecords();
   1747                 if (mIsSubscriptionFromRuim) {
   1748                     mUiccApplcation.registerForReady(this, EVENT_RUIM_READY, null);
   1749                     if (mIccRecords != null) {
   1750                         mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
   1751                     }
   1752                 }
   1753             }
   1754         }
   1755     }
   1756 
   1757     @Override
   1758     protected void log(String s) {
   1759         Rlog.d(LOG_TAG, "[CdmaSST] " + s);
   1760     }
   1761 
   1762     @Override
   1763     protected void loge(String s) {
   1764         Rlog.e(LOG_TAG, "[CdmaSST] " + s);
   1765     }
   1766 
   1767     @Override
   1768     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1769         pw.println("CdmaServiceStateTracker extends:");
   1770         super.dump(fd, pw, args);
   1771         pw.println(" mPhone=" + mPhone);
   1772         pw.println(" mSS=" + mSS);
   1773         pw.println(" mNewSS=" + mNewSS);
   1774         pw.println(" mCellLoc=" + mCellLoc);
   1775         pw.println(" mNewCellLoc=" + mNewCellLoc);
   1776         pw.println(" mCurrentOtaspMode=" + mCurrentOtaspMode);
   1777         pw.println(" mCdmaRoaming=" + mCdmaRoaming);
   1778         pw.println(" mRoamingIndicator=" + mRoamingIndicator);
   1779         pw.println(" mIsInPrl=" + mIsInPrl);
   1780         pw.println(" mDefaultRoamingIndicator=" + mDefaultRoamingIndicator);
   1781         pw.println(" mRegistrationState=" + mRegistrationState);
   1782         pw.println(" mNeedFixZone=" + mNeedFixZone);
   1783         pw.println(" mZoneOffset=" + mZoneOffset);
   1784         pw.println(" mZoneDst=" + mZoneDst);
   1785         pw.println(" mZoneTime=" + mZoneTime);
   1786         pw.println(" mGotCountryCode=" + mGotCountryCode);
   1787         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
   1788         pw.println(" mSavedTime=" + mSavedTime);
   1789         pw.println(" mSavedAtTime=" + mSavedAtTime);
   1790         pw.println(" mWakeLock=" + mWakeLock);
   1791         pw.println(" mCurPlmn=" + mCurPlmn);
   1792         pw.println(" mMdn=" + mMdn);
   1793         pw.println(" mHomeSystemId=" + mHomeSystemId);
   1794         pw.println(" mHomeNetworkId=" + mHomeNetworkId);
   1795         pw.println(" mMin=" + mMin);
   1796         pw.println(" mPrlVersion=" + mPrlVersion);
   1797         pw.println(" mIsMinInfoReady=" + mIsMinInfoReady);
   1798         pw.println(" mIsEriTextLoaded=" + mIsEriTextLoaded);
   1799         pw.println(" mIsSubscriptionFromRuim=" + mIsSubscriptionFromRuim);
   1800         pw.println(" mCdmaSSM=" + mCdmaSSM);
   1801         pw.println(" mRegistrationDeniedReason=" + mRegistrationDeniedReason);
   1802         pw.println(" mCurrentCarrier=" + mCurrentCarrier);
   1803     }
   1804 }
   1805