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