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