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