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