GsmServiceStateTracker.java revision b54cd09892e0676d719e6df00e60c77b663f993c
1/*
2 * Copyright (C) 2006 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.gsm;
18
19import android.app.AlarmManager;
20import android.app.Notification;
21import android.app.NotificationManager;
22import android.app.PendingIntent;
23import android.content.BroadcastReceiver;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.res.Resources;
29import android.database.ContentObserver;
30import android.os.AsyncResult;
31import android.os.Build;
32import android.os.Handler;
33import android.os.Message;
34import android.os.PowerManager;
35import android.os.SystemClock;
36import android.os.SystemProperties;
37import android.os.UserHandle;
38import android.provider.Settings;
39import android.provider.Settings.SettingNotFoundException;
40import android.telephony.CellIdentityGsm;
41import android.telephony.CellIdentityLte;
42import android.telephony.CellIdentityWcdma;
43import android.telephony.CellInfo;
44import android.telephony.CellInfoGsm;
45import android.telephony.CellInfoLte;
46import android.telephony.CellInfoWcdma;
47import android.telephony.CellLocation;
48import android.telephony.Rlog;
49import android.telephony.ServiceState;
50import android.telephony.SignalStrength;
51import android.telephony.gsm.GsmCellLocation;
52import android.text.TextUtils;
53import android.util.EventLog;
54import android.util.TimeUtils;
55
56import com.android.internal.telephony.CommandException;
57import com.android.internal.telephony.CommandsInterface;
58import com.android.internal.telephony.EventLogTags;
59import com.android.internal.telephony.MccTable;
60import com.android.internal.telephony.Phone;
61import com.android.internal.telephony.RILConstants;
62import com.android.internal.telephony.RestrictedState;
63import com.android.internal.telephony.ServiceStateTracker;
64import com.android.internal.telephony.TelephonyIntents;
65import com.android.internal.telephony.TelephonyProperties;
66import com.android.internal.telephony.dataconnection.DcTrackerBase;
67import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
68import com.android.internal.telephony.uicc.IccRecords;
69import com.android.internal.telephony.uicc.SIMRecords;
70import com.android.internal.telephony.uicc.UiccCardApplication;
71import com.android.internal.telephony.uicc.UiccController;
72
73import java.io.FileDescriptor;
74import java.io.PrintWriter;
75import java.util.ArrayList;
76import java.util.Arrays;
77import java.util.Calendar;
78import java.util.Date;
79import java.util.List;
80import java.util.TimeZone;
81
82/**
83 * {@hide}
84 */
85final class GsmServiceStateTracker extends ServiceStateTracker {
86    private static final String LOG_TAG = "GsmSST";
87    private static final boolean VDBG = false;
88
89    GSMPhone mPhone;
90    GsmCellLocation mCellLoc;
91    GsmCellLocation mNewCellLoc;
92    int mPreferredNetworkType;
93
94    private int mMaxDataCalls = 1;
95    private int mNewMaxDataCalls = 1;
96    private int mReasonDataDenied = -1;
97    private int mNewReasonDataDenied = -1;
98
99    /**
100     * GSM roaming status solely based on TS 27.007 7.2 CREG. Only used by
101     * handlePollStateResult to store CREG roaming result.
102     */
103    private boolean mGsmRoaming = false;
104
105    /**
106     * Data roaming status solely based on TS 27.007 10.1.19 CGREG. Only used by
107     * handlePollStateResult to store CGREG roaming result.
108     */
109    private boolean mDataRoaming = false;
110
111    /**
112     * Mark when service state is in emergency call only mode
113     */
114    private boolean mEmergencyOnly = false;
115
116    /**
117     * Sometimes we get the NITZ time before we know what country we
118     * are in. Keep the time zone information from the NITZ string so
119     * we can fix the time zone once know the country.
120     */
121    private boolean mNeedFixZoneAfterNitz = false;
122    private int mZoneOffset;
123    private boolean mZoneDst;
124    private long mZoneTime;
125    private boolean mGotCountryCode = false;
126    private ContentResolver mCr;
127
128    /** Boolean is true is setTimeFromNITZString was called */
129    private boolean mNitzUpdatedTime = false;
130
131    String mSavedTimeZone;
132    long mSavedTime;
133    long mSavedAtTime;
134
135    /** Started the recheck process after finding gprs should registered but not. */
136    private boolean mStartedGprsRegCheck = false;
137
138    /** Already sent the event-log for no gprs register. */
139    private boolean mReportedGprsNoReg = false;
140
141    /**
142     * The Notification object given to the NotificationManager.
143     */
144    private Notification mNotification;
145
146    /** Wake lock used while setting time of day. */
147    private PowerManager.WakeLock mWakeLock;
148    private static final String WAKELOCK_TAG = "ServiceStateTracker";
149
150    /** Keep track of SPN display rules, so we only broadcast intent if something changes. */
151    private String mCurSpn = null;
152    private String mCurPlmn = null;
153    private boolean mCurShowPlmn = false;
154    private boolean mCurShowSpn = false;
155
156    /** Notification type. */
157    static final int PS_ENABLED = 1001;            // Access Control blocks data service
158    static final int PS_DISABLED = 1002;           // Access Control enables data service
159    static final int CS_ENABLED = 1003;            // Access Control blocks all voice/sms service
160    static final int CS_DISABLED = 1004;           // Access Control enables all voice/sms service
161    static final int CS_NORMAL_ENABLED = 1005;     // Access Control blocks normal voice/sms service
162    static final int CS_EMERGENCY_ENABLED = 1006;  // Access Control blocks emergency call service
163
164    /** Notification id. */
165    static final int PS_NOTIFICATION = 888;  // Id to update and cancel PS restricted
166    static final int CS_NOTIFICATION = 999;  // Id to update and cancel CS restricted
167
168    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
169        @Override
170        public void onReceive(Context context, Intent intent) {
171            if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
172                // update emergency string whenever locale changed
173                updateSpnDisplay();
174            }
175        }
176    };
177
178    private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
179        @Override
180        public void onChange(boolean selfChange) {
181            Rlog.i("GsmServiceStateTracker", "Auto time state changed");
182            revertToNitzTime();
183        }
184    };
185
186    private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
187        @Override
188        public void onChange(boolean selfChange) {
189            Rlog.i("GsmServiceStateTracker", "Auto time zone state changed");
190            revertToNitzTimeZone();
191        }
192    };
193
194    public GsmServiceStateTracker(GSMPhone phone) {
195        super(phone, phone.mCi, new CellInfoGsm());
196
197        mPhone = phone;
198        mCellLoc = new GsmCellLocation();
199        mNewCellLoc = new GsmCellLocation();
200
201        PowerManager powerManager =
202                (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
203        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
204
205        mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
206        mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
207
208        mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
209        mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
210        mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
211
212        // system setting property AIRPLANE_MODE_ON is set in Settings.
213        int airplaneMode = Settings.Global.getInt(
214                phone.getContext().getContentResolver(),
215                Settings.Global.AIRPLANE_MODE_ON, 0);
216        mDesiredPowerState = ! (airplaneMode > 0);
217
218        mCr = phone.getContext().getContentResolver();
219        mCr.registerContentObserver(
220                Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
221                mAutoTimeObserver);
222        mCr.registerContentObserver(
223                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
224                mAutoTimeZoneObserver);
225
226        setSignalStrengthDefaultValues();
227
228        // Monitor locale change
229        IntentFilter filter = new IntentFilter();
230        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
231        phone.getContext().registerReceiver(mIntentReceiver, filter);
232
233        // Gsm doesn't support OTASP so its not needed
234        phone.notifyOtaspChanged(OTASP_NOT_NEEDED);
235    }
236
237    @Override
238    public void dispose() {
239        checkCorrectThread();
240        // Unregister for all events.
241        mCi.unregisterForAvailable(this);
242        mCi.unregisterForRadioStateChanged(this);
243        mCi.unregisterForVoiceNetworkStateChanged(this);
244        if (mUiccApplcation != null) {mUiccApplcation.unregisterForReady(this);}
245        if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
246        mCi.unSetOnRestrictedStateChanged(this);
247        mCi.unSetOnNITZTime(this);
248        mCr.unregisterContentObserver(mAutoTimeObserver);
249        mCr.unregisterContentObserver(mAutoTimeZoneObserver);
250        mPhone.getContext().unregisterReceiver(mIntentReceiver);
251        super.dispose();
252    }
253
254    @Override
255    protected void finalize() {
256        if(DBG) log("finalize");
257    }
258
259    @Override
260    protected Phone getPhone() {
261        return mPhone;
262    }
263
264    @Override
265    public void handleMessage (Message msg) {
266        AsyncResult ar;
267        int[] ints;
268        String[] strings;
269        Message message;
270
271        if (!mPhone.mIsTheCurrentActivePhone) {
272            Rlog.e(LOG_TAG, "Received message " + msg +
273                    "[" + msg.what + "] while being destroyed. Ignoring.");
274            return;
275        }
276        switch (msg.what) {
277            case EVENT_RADIO_AVAILABLE:
278                //this is unnecessary
279                //setPowerStateToDesired();
280                break;
281
282            case EVENT_SIM_READY:
283                // Set the network type, in case the radio does not restore it.
284                mCi.setCurrentPreferredNetworkType();
285
286                boolean skipRestoringSelection = mPhone.getContext().getResources().getBoolean(
287                        com.android.internal.R.bool.skip_restoring_network_selection);
288
289                if (!skipRestoringSelection) {
290                    // restore the previous network selection.
291                    mPhone.restoreSavedNetworkSelection(null);
292                }
293                pollState();
294                // Signal strength polling stops when radio is off
295                queueNextSignalStrengthPoll();
296                break;
297
298            case EVENT_RADIO_STATE_CHANGED:
299                // This will do nothing in the radio not
300                // available case
301                setPowerStateToDesired();
302                pollState();
303                break;
304
305            case EVENT_NETWORK_STATE_CHANGED:
306                pollState();
307                break;
308
309            case EVENT_GET_SIGNAL_STRENGTH:
310                // This callback is called when signal strength is polled
311                // all by itself
312
313                if (!(mCi.getRadioState().isOn())) {
314                    // Polling will continue when radio turns back on
315                    return;
316                }
317                ar = (AsyncResult) msg.obj;
318                onSignalStrengthResult(ar, true);
319                queueNextSignalStrengthPoll();
320
321                break;
322
323            case EVENT_GET_LOC_DONE:
324                ar = (AsyncResult) msg.obj;
325
326                if (ar.exception == null) {
327                    String states[] = (String[])ar.result;
328                    int lac = -1;
329                    int cid = -1;
330                    if (states.length >= 3) {
331                        try {
332                            if (states[1] != null && states[1].length() > 0) {
333                                lac = Integer.parseInt(states[1], 16);
334                            }
335                            if (states[2] != null && states[2].length() > 0) {
336                                cid = Integer.parseInt(states[2], 16);
337                            }
338                        } catch (NumberFormatException ex) {
339                            Rlog.w(LOG_TAG, "error parsing location: " + ex);
340                        }
341                    }
342                    mCellLoc.setLacAndCid(lac, cid);
343                    mPhone.notifyLocationChanged();
344                }
345
346                // Release any temporary cell lock, which could have been
347                // acquired to allow a single-shot location update.
348                disableSingleLocationUpdate();
349                break;
350
351            case EVENT_POLL_STATE_REGISTRATION:
352            case EVENT_POLL_STATE_GPRS:
353            case EVENT_POLL_STATE_OPERATOR:
354            case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
355                ar = (AsyncResult) msg.obj;
356
357                handlePollStateResult(msg.what, ar);
358                break;
359
360            case EVENT_POLL_SIGNAL_STRENGTH:
361                // Just poll signal strength...not part of pollState()
362
363                mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
364                break;
365
366            case EVENT_NITZ_TIME:
367                ar = (AsyncResult) msg.obj;
368
369                String nitzString = (String)((Object[])ar.result)[0];
370                long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
371
372                setTimeFromNITZString(nitzString, nitzReceiveTime);
373                break;
374
375            case EVENT_SIGNAL_STRENGTH_UPDATE:
376                // This is a notification from
377                // CommandsInterface.setOnSignalStrengthUpdate
378
379                ar = (AsyncResult) msg.obj;
380
381                // The radio is telling us about signal strength changes
382                // we don't have to ask it
383                mDontPollSignalStrength = true;
384
385                onSignalStrengthResult(ar, true);
386                break;
387
388            case EVENT_SIM_RECORDS_LOADED:
389                log("EVENT_SIM_RECORDS_LOADED: what=" + msg.what);
390
391                updatePhoneObject();
392                updateSpnDisplay();
393                break;
394
395            case EVENT_LOCATION_UPDATES_ENABLED:
396                ar = (AsyncResult) msg.obj;
397
398                if (ar.exception == null) {
399                    mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null));
400                }
401                break;
402
403            case EVENT_SET_PREFERRED_NETWORK_TYPE:
404                ar = (AsyncResult) msg.obj;
405                // Don't care the result, only use for dereg network (COPS=2)
406                message = obtainMessage(EVENT_RESET_PREFERRED_NETWORK_TYPE, ar.userObj);
407                mCi.setPreferredNetworkType(mPreferredNetworkType, message);
408                break;
409
410            case EVENT_RESET_PREFERRED_NETWORK_TYPE:
411                ar = (AsyncResult) msg.obj;
412                if (ar.userObj != null) {
413                    AsyncResult.forMessage(((Message) ar.userObj)).exception
414                            = ar.exception;
415                    ((Message) ar.userObj).sendToTarget();
416                }
417                break;
418
419            case EVENT_GET_PREFERRED_NETWORK_TYPE:
420                ar = (AsyncResult) msg.obj;
421
422                if (ar.exception == null) {
423                    mPreferredNetworkType = ((int[])ar.result)[0];
424                } else {
425                    mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
426                }
427
428                message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj);
429                int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
430
431                mCi.setPreferredNetworkType(toggledNetworkType, message);
432                break;
433
434            case EVENT_CHECK_REPORT_GPRS:
435                if (mSS != null && !isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
436
437                    // Can't register data service while voice service is ok
438                    // i.e. CREG is ok while CGREG is not
439                    // possible a network or baseband side error
440                    GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
441                    EventLog.writeEvent(EventLogTags.DATA_NETWORK_REGISTRATION_FAIL,
442                            mSS.getOperatorNumeric(), loc != null ? loc.getCid() : -1);
443                    mReportedGprsNoReg = true;
444                }
445                mStartedGprsRegCheck = false;
446                break;
447
448            case EVENT_RESTRICTED_STATE_CHANGED:
449                // This is a notification from
450                // CommandsInterface.setOnRestrictedStateChanged
451
452                if (DBG) log("EVENT_RESTRICTED_STATE_CHANGED");
453
454                ar = (AsyncResult) msg.obj;
455
456                onRestrictedStateChanged(ar);
457                break;
458
459            default:
460                super.handleMessage(msg);
461            break;
462        }
463    }
464
465    @Override
466    protected void setPowerStateToDesired() {
467        // If we want it on and it's off, turn it on
468        if (mDesiredPowerState
469            && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
470            mCi.setRadioPower(true, null);
471        } else if (!mDesiredPowerState && mCi.getRadioState().isOn()) {
472            // If it's on and available and we want it off gracefully
473            DcTrackerBase dcTracker = mPhone.mDcTracker;
474            powerOffRadioSafely(dcTracker);
475        } // Otherwise, we're in the desired state
476    }
477
478    @Override
479    protected void hangupAndPowerOff() {
480        // hang up all active voice calls
481        if (mPhone.isInCall()) {
482            mPhone.mCT.mRingingCall.hangupIfAlive();
483            mPhone.mCT.mBackgroundCall.hangupIfAlive();
484            mPhone.mCT.mForegroundCall.hangupIfAlive();
485        }
486
487        mCi.setRadioPower(false, null);
488    }
489
490    @Override
491    protected void updateSpnDisplay() {
492        // The values of plmn/showPlmn change in different scenarios.
493        // 1) No service but emergency call allowed -> expected
494        //    to show "Emergency call only"
495        //    EXTRA_SHOW_PLMN = true
496        //    EXTRA_PLMN = "Emergency call only"
497
498        // 2) No service at all --> expected to show "No service"
499        //    EXTRA_SHOW_PLMN = true
500        //    EXTRA_PLMN = "No service"
501
502        // 3) Normal operation in either home or roaming service
503        //    EXTRA_SHOW_PLMN = depending on IccRecords rule
504        //    EXTRA_PLMN = plmn
505
506        // 4) No service due to power off, aka airplane mode
507        //    EXTRA_SHOW_PLMN = false
508        //    EXTRA_PLMN = null
509
510        IccRecords iccRecords = mIccRecords;
511        String plmn = null;
512        boolean showPlmn = false;
513        int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0;
514        if (mSS.getVoiceRegState() == ServiceState.STATE_OUT_OF_SERVICE
515                || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY) {
516            showPlmn = true;
517            if (mEmergencyOnly) {
518                // No service but emergency call allowed
519                plmn = Resources.getSystem().
520                        getText(com.android.internal.R.string.emergency_calls_only).toString();
521            } else {
522                // No service at all
523                plmn = Resources.getSystem().
524                        getText(com.android.internal.R.string.lockscreen_carrier_default).toString();
525            }
526            if (DBG) log("updateSpnDisplay: radio is on but out " +
527                    "of service, set plmn='" + plmn + "'");
528        } else if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
529            // In either home or roaming service
530            plmn = mSS.getOperatorAlphaLong();
531            showPlmn = !TextUtils.isEmpty(plmn) &&
532                    ((rule & SIMRecords.SPN_RULE_SHOW_PLMN)
533                            == SIMRecords.SPN_RULE_SHOW_PLMN);
534        } else {
535            // Power off state, such as airplane mode
536            if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn="
537                    + showPlmn + " plmn=" + plmn);
538        }
539
540        // The value of spn/showSpn are same in different scenarios.
541        //    EXTRA_SHOW_SPN = depending on IccRecords rule
542        //    EXTRA_SPN = spn
543        String spn = (iccRecords != null) ? iccRecords.getServiceProviderName() : "";
544        boolean showSpn = !TextUtils.isEmpty(spn)
545                && ((rule & SIMRecords.SPN_RULE_SHOW_SPN)
546                        == SIMRecords.SPN_RULE_SHOW_SPN);
547
548        // Update SPN_STRINGS_UPDATED_ACTION IFF any value changes
549        if (showPlmn != mCurShowPlmn
550                || showSpn != mCurShowSpn
551                || !TextUtils.equals(spn, mCurSpn)
552                || !TextUtils.equals(plmn, mCurPlmn)) {
553            if (DBG) {
554                log(String.format("updateSpnDisplay: changed" +
555                        " sending intent rule=" + rule +
556                        " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s'",
557                        showPlmn, plmn, showSpn, spn));
558            }
559            Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
560            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
561            intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn);
562            intent.putExtra(TelephonyIntents.EXTRA_SPN, spn);
563            intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
564            intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
565            mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
566        }
567
568        mCurShowSpn = showSpn;
569        mCurShowPlmn = showPlmn;
570        mCurSpn = spn;
571        mCurPlmn = plmn;
572    }
573
574    /**
575     * Handle the result of one of the pollState()-related requests
576     */
577    @Override
578    protected void handlePollStateResult (int what, AsyncResult ar) {
579        int ints[];
580        String states[];
581
582        // Ignore stale requests from last poll
583        if (ar.userObj != mPollingContext) return;
584
585        if (ar.exception != null) {
586            CommandException.Error err=null;
587
588            if (ar.exception instanceof CommandException) {
589                err = ((CommandException)(ar.exception)).getCommandError();
590            }
591
592            if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
593                // Radio has crashed or turned off
594                cancelPollState();
595                return;
596            }
597
598            if (!mCi.getRadioState().isOn()) {
599                // Radio has crashed or turned off
600                cancelPollState();
601                return;
602            }
603
604            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
605                loge("RIL implementation has returned an error where it must succeed" +
606                        ar.exception);
607            }
608        } else try {
609            switch (what) {
610                case EVENT_POLL_STATE_REGISTRATION: {
611                    states = (String[])ar.result;
612                    int lac = -1;
613                    int cid = -1;
614                    int type = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
615                    int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
616                    int reasonRegStateDenied = -1;
617                    int psc = -1;
618                    if (states.length > 0) {
619                        try {
620                            regState = Integer.parseInt(states[0]);
621                            if (states.length >= 3) {
622                                if (states[1] != null && states[1].length() > 0) {
623                                    lac = Integer.parseInt(states[1], 16);
624                                }
625                                if (states[2] != null && states[2].length() > 0) {
626                                    cid = Integer.parseInt(states[2], 16);
627                                }
628
629                                // states[3] (if present) is the current radio technology
630                                if (states.length >= 4 && states[3] != null) {
631                                    type = Integer.parseInt(states[3]);
632                                }
633                            }
634                            if (states.length > 14) {
635                                if (states[14] != null && states[14].length() > 0) {
636                                    psc = Integer.parseInt(states[14], 16);
637                                }
638                            }
639                        } catch (NumberFormatException ex) {
640                            loge("error parsing RegistrationState: " + ex);
641                        }
642                    }
643
644                    mGsmRoaming = regCodeIsRoaming(regState);
645                    mNewSS.setState(regCodeToServiceState(regState));
646                    mNewSS.setRilVoiceRadioTechnology(type);
647
648                    boolean isVoiceCapable = mPhoneBase.getContext().getResources()
649                            .getBoolean(com.android.internal.R.bool.config_voice_capable);
650                    if ((regState == ServiceState.RIL_REG_STATE_DENIED_EMERGENCY_CALL_ENABLED
651                         || regState == ServiceState.RIL_REG_STATE_NOT_REG_EMERGENCY_CALL_ENABLED
652                         || regState == ServiceState.RIL_REG_STATE_SEARCHING_EMERGENCY_CALL_ENABLED
653                         || regState == ServiceState.RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED)
654                         && isVoiceCapable) {
655                        mEmergencyOnly = true;
656                    } else {
657                        mEmergencyOnly = false;
658                    }
659
660                    // LAC and CID are -1 if not avail
661                    mNewCellLoc.setLacAndCid(lac, cid);
662                    mNewCellLoc.setPsc(psc);
663                    break;
664                }
665
666                case EVENT_POLL_STATE_GPRS: {
667                    states = (String[])ar.result;
668
669                    int type = 0;
670                    int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
671                    mNewReasonDataDenied = -1;
672                    mNewMaxDataCalls = 1;
673                    if (states.length > 0) {
674                        try {
675                            regState = Integer.parseInt(states[0]);
676
677                            // states[3] (if present) is the current radio technology
678                            if (states.length >= 4 && states[3] != null) {
679                                type = Integer.parseInt(states[3]);
680                            }
681                            if ((states.length >= 5 ) &&
682                                    (regState == ServiceState.RIL_REG_STATE_DENIED)) {
683                                mNewReasonDataDenied = Integer.parseInt(states[4]);
684                            }
685                            if (states.length >= 6) {
686                                mNewMaxDataCalls = Integer.parseInt(states[5]);
687                            }
688                        } catch (NumberFormatException ex) {
689                            loge("error parsing GprsRegistrationState: " + ex);
690                        }
691                    }
692                    int dataRegState = regCodeToServiceState(regState);
693                    mNewSS.setDataRegState(dataRegState);
694                    mDataRoaming = regCodeIsRoaming(regState);
695                    mNewSS.setRilDataRadioTechnology(type);
696                    if (DBG) {
697                        log("handlPollStateResultMessage: GsmSST setDataRegState=" + dataRegState
698                                + " regState=" + regState
699                                + " dataRadioTechnology=" + type);
700                    }
701                    break;
702                }
703
704                case EVENT_POLL_STATE_OPERATOR: {
705                    String opNames[] = (String[])ar.result;
706
707                    if (opNames != null && opNames.length >= 3) {
708                         mNewSS.setOperatorName (opNames[0], opNames[1], opNames[2]);
709                    }
710                    break;
711                }
712
713                case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: {
714                    ints = (int[])ar.result;
715                    mNewSS.setIsManualSelection(ints[0] == 1);
716                    break;
717                }
718            }
719
720        } catch (RuntimeException ex) {
721            loge("Exception while polling service state. Probably malformed RIL response." + ex);
722        }
723
724        mPollingContext[0]--;
725
726        if (mPollingContext[0] == 0) {
727            /**
728             * Since the roaming state of gsm service (from +CREG) and
729             * data service (from +CGREG) could be different, the new SS
730             * is set to roaming when either is true.
731             *
732             * There are exceptions for the above rule.
733             * The new SS is not set as roaming while gsm service reports
734             * roaming but indeed it is same operator.
735             * And the operator is considered non roaming.
736             *
737             * The test for the operators is to handle special roaming
738             * agreements and MVNO's.
739             */
740            boolean roaming = (mGsmRoaming || mDataRoaming);
741            if ((mGsmRoaming && isSameNamedOperators(mNewSS))
742                    || isOperatorConsideredNonRoaming(mNewSS)) {
743                roaming = false;
744            }
745            mNewSS.setRoaming(roaming);
746            mNewSS.setEmergencyOnly(mEmergencyOnly);
747            pollStateDone();
748        }
749    }
750
751    private void setSignalStrengthDefaultValues() {
752        mSignalStrength = new SignalStrength(true);
753    }
754
755    /**
756     * A complete "service state" from our perspective is
757     * composed of a handful of separate requests to the radio.
758     *
759     * We make all of these requests at once, but then abandon them
760     * and start over again if the radio notifies us that some
761     * event has changed
762     */
763    private void pollState() {
764        mPollingContext = new int[1];
765        mPollingContext[0] = 0;
766
767        switch (mCi.getRadioState()) {
768            case RADIO_UNAVAILABLE:
769                mNewSS.setStateOutOfService();
770                mNewCellLoc.setStateInvalid();
771                setSignalStrengthDefaultValues();
772                mGotCountryCode = false;
773                mNitzUpdatedTime = false;
774                pollStateDone();
775            break;
776
777            case RADIO_OFF:
778                mNewSS.setStateOff();
779                mNewCellLoc.setStateInvalid();
780                setSignalStrengthDefaultValues();
781                mGotCountryCode = false;
782                mNitzUpdatedTime = false;
783                pollStateDone();
784            break;
785
786            default:
787                // Issue all poll-related commands at once
788                // then count down the responses, which
789                // are allowed to arrive out-of-order
790
791                mPollingContext[0]++;
792                mCi.getOperator(
793                    obtainMessage(
794                        EVENT_POLL_STATE_OPERATOR, mPollingContext));
795
796                mPollingContext[0]++;
797                mCi.getDataRegistrationState(
798                    obtainMessage(
799                        EVENT_POLL_STATE_GPRS, mPollingContext));
800
801                mPollingContext[0]++;
802                mCi.getVoiceRegistrationState(
803                    obtainMessage(
804                        EVENT_POLL_STATE_REGISTRATION, mPollingContext));
805
806                mPollingContext[0]++;
807                mCi.getNetworkSelectionMode(
808                    obtainMessage(
809                        EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));
810            break;
811        }
812    }
813
814    private void pollStateDone() {
815        if (DBG) {
816            log("Poll ServiceState done: " +
817                " oldSS=[" + mSS + "] newSS=[" + mNewSS + "]" +
818                " oldMaxDataCalls=" + mMaxDataCalls +
819                " mNewMaxDataCalls=" + mNewMaxDataCalls +
820                " oldReasonDataDenied=" + mReasonDataDenied +
821                " mNewReasonDataDenied=" + mNewReasonDataDenied);
822        }
823
824        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
825            mNewSS.setRoaming(true);
826        }
827
828        useDataRegStateForDataOnlyDevices();
829
830        boolean hasRegistered =
831            mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
832            && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
833
834        boolean hasDeregistered =
835            mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
836            && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
837
838        boolean hasGprsAttached =
839                mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
840                && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
841
842        boolean hasGprsDetached =
843                mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
844                && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
845
846        boolean hasDataRegStateChanged =
847                mSS.getDataRegState() != mNewSS.getDataRegState();
848
849        boolean hasVoiceRegStateChanged =
850                mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
851
852        boolean hasRilVoiceRadioTechnologyChanged =
853                mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
854
855        boolean hasRilDataRadioTechnologyChanged =
856                mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
857
858        boolean hasChanged = !mNewSS.equals(mSS);
859
860        boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
861
862        boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
863
864        boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
865
866        // Add an event log when connection state changes
867        if (hasVoiceRegStateChanged || hasDataRegStateChanged) {
868            EventLog.writeEvent(EventLogTags.GSM_SERVICE_STATE_CHANGE,
869                mSS.getVoiceRegState(), mSS.getDataRegState(),
870                mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
871        }
872
873        // Add an event log when network type switched
874        // TODO: we may add filtering to reduce the event logged,
875        // i.e. check preferred network setting, only switch to 2G, etc
876        if (hasRilVoiceRadioTechnologyChanged) {
877            int cid = -1;
878            GsmCellLocation loc = mNewCellLoc;
879            if (loc != null) cid = loc.getCid();
880            // NOTE: this code was previously located after mSS and mNewSS are swapped, so
881            // existing logs were incorrectly using the new state for "network_from"
882            // and STATE_OUT_OF_SERVICE for "network_to". To avoid confusion, use a new log tag
883            // to record the correct states.
884            EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED_NEW, cid,
885                    mSS.getRilVoiceRadioTechnology(),
886                    mNewSS.getRilVoiceRadioTechnology());
887            if (DBG) {
888                log("RAT switched "
889                        + ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology())
890                        + " -> "
891                        + ServiceState.rilRadioTechnologyToString(
892                                mNewSS.getRilVoiceRadioTechnology()) + " at cell " + cid);
893            }
894        }
895
896        // swap mSS and mNewSS to put new state in mSS
897        ServiceState tss = mSS;
898        mSS = mNewSS;
899        mNewSS = tss;
900        // clean slate for next time
901        mNewSS.setStateOutOfService();
902
903        // swap mCellLoc and mNewCellLoc to put new state in mCellLoc
904        GsmCellLocation tcl = mCellLoc;
905        mCellLoc = mNewCellLoc;
906        mNewCellLoc = tcl;
907
908        mReasonDataDenied = mNewReasonDataDenied;
909        mMaxDataCalls = mNewMaxDataCalls;
910
911        if (hasRilVoiceRadioTechnologyChanged) {
912            updatePhoneObject();
913        }
914
915        if (hasRilDataRadioTechnologyChanged) {
916            mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
917                    ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology()));
918        }
919
920        if (hasRegistered) {
921            mNetworkAttachedRegistrants.notifyRegistrants();
922
923            if (DBG) {
924                log("pollStateDone: registering current mNitzUpdatedTime=" +
925                        mNitzUpdatedTime + " changing to false");
926            }
927            mNitzUpdatedTime = false;
928        }
929
930        if (hasChanged) {
931            String operatorNumeric;
932
933            updateSpnDisplay();
934
935            mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
936                mSS.getOperatorAlphaLong());
937
938            String prevOperatorNumeric =
939                    SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
940            operatorNumeric = mSS.getOperatorNumeric();
941            mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
942
943            if (operatorNumeric == null) {
944                if (DBG) log("operatorNumeric is null");
945                mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
946                mGotCountryCode = false;
947                mNitzUpdatedTime = false;
948            } else {
949                String iso = "";
950                String mcc = "";
951                try{
952                    mcc = operatorNumeric.substring(0, 3);
953                    iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc));
954                } catch ( NumberFormatException ex){
955                    loge("pollStateDone: countryCodeForMcc error" + ex);
956                } catch ( StringIndexOutOfBoundsException ex) {
957                    loge("pollStateDone: countryCodeForMcc error" + ex);
958                }
959
960                mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso);
961                mGotCountryCode = true;
962
963                TimeZone zone = null;
964
965                if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) &&
966                        getAutoTimeZone()) {
967
968                    // Test both paths if ignore nitz is true
969                    boolean testOneUniqueOffsetPath = SystemProperties.getBoolean(
970                                TelephonyProperties.PROPERTY_IGNORE_NITZ, false) &&
971                                    ((SystemClock.uptimeMillis() & 1) == 0);
972
973                    ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso);
974                    if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) {
975                        zone = uniqueZones.get(0);
976                        if (DBG) {
977                           log("pollStateDone: no nitz but one TZ for iso-cc=" + iso +
978                                   " with zone.getID=" + zone.getID() +
979                                   " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
980                        }
981                        setAndBroadcastNetworkSetTimeZone(zone.getID());
982                    } else {
983                        if (DBG) {
984                            log("pollStateDone: there are " + uniqueZones.size() +
985                                " unique offsets for iso-cc='" + iso +
986                                " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath +
987                                "', do nothing");
988                        }
989                    }
990                }
991
992                if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
993                        mNeedFixZoneAfterNitz)) {
994                    // If the offset is (0, false) and the timezone property
995                    // is set, use the timezone property rather than
996                    // GMT.
997                    String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
998                    if (DBG) {
999                        log("pollStateDone: fix time zone zoneName='" + zoneName +
1000                            "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
1001                            " iso-cc='" + iso +
1002                            "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso));
1003                    }
1004
1005                    // "(mZoneOffset == 0) && (mZoneDst == false) &&
1006                    //  (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)"
1007                    // means that we received a NITZ string telling
1008                    // it is in GMT+0 w/ DST time zone
1009                    // BUT iso tells is NOT, e.g, a wrong NITZ reporting
1010                    // local time w/ 0 offset.
1011                    if ((mZoneOffset == 0) && (mZoneDst == false) &&
1012                        (zoneName != null) && (zoneName.length() > 0) &&
1013                        (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) {
1014                        zone = TimeZone.getDefault();
1015                        if (mNeedFixZoneAfterNitz) {
1016                            // For wrong NITZ reporting local time w/ 0 offset,
1017                            // need adjust time to reflect default timezone setting
1018                            long ctm = System.currentTimeMillis();
1019                            long tzOffset = zone.getOffset(ctm);
1020                            if (DBG) {
1021                                log("pollStateDone: tzOffset=" + tzOffset + " ltod=" +
1022                                        TimeUtils.logTimeOfDay(ctm));
1023                            }
1024                            if (getAutoTime()) {
1025                                long adj = ctm - tzOffset;
1026                                if (DBG) log("pollStateDone: adj ltod=" +
1027                                        TimeUtils.logTimeOfDay(adj));
1028                                setAndBroadcastNetworkSetTime(adj);
1029                            } else {
1030                                // Adjust the saved NITZ time to account for tzOffset.
1031                                mSavedTime = mSavedTime - tzOffset;
1032                            }
1033                        }
1034                        if (DBG) log("pollStateDone: using default TimeZone");
1035                    } else if (iso.equals("")){
1036                        // Country code not found.  This is likely a test network.
1037                        // Get a TimeZone based only on the NITZ parameters (best guess).
1038                        zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
1039                        if (DBG) log("pollStateDone: using NITZ TimeZone");
1040                    } else {
1041                        zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, iso);
1042                        if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)");
1043                    }
1044
1045                    mNeedFixZoneAfterNitz = false;
1046
1047                    if (zone != null) {
1048                        log("pollStateDone: zone != null zone.getID=" + zone.getID());
1049                        if (getAutoTimeZone()) {
1050                            setAndBroadcastNetworkSetTimeZone(zone.getID());
1051                        }
1052                        saveNitzTimeZone(zone.getID());
1053                    } else {
1054                        log("pollStateDone: zone == null");
1055                    }
1056                }
1057            }
1058
1059            mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
1060                mSS.getRoaming() ? "true" : "false");
1061
1062            mPhone.notifyServiceStateChanged(mSS);
1063        }
1064
1065        if (hasGprsAttached) {
1066            mAttachedRegistrants.notifyRegistrants();
1067        }
1068
1069        if (hasGprsDetached) {
1070            mDetachedRegistrants.notifyRegistrants();
1071        }
1072
1073        if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
1074            notifyDataRegStateRilRadioTechnologyChanged();
1075            mPhone.notifyDataConnection(null);
1076        }
1077
1078        if (hasRoamingOn) {
1079            mRoamingOnRegistrants.notifyRegistrants();
1080        }
1081
1082        if (hasRoamingOff) {
1083            mRoamingOffRegistrants.notifyRegistrants();
1084        }
1085
1086        if (hasLocationChanged) {
1087            mPhone.notifyLocationChanged();
1088        }
1089
1090        if (! isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
1091            if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
1092                mStartedGprsRegCheck = true;
1093
1094                int check_period = Settings.Global.getInt(
1095                        mPhone.getContext().getContentResolver(),
1096                        Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
1097                        DEFAULT_GPRS_CHECK_PERIOD_MILLIS);
1098                sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS),
1099                        check_period);
1100            }
1101        } else {
1102            mReportedGprsNoReg = false;
1103        }
1104        // TODO: Add GsmCellIdenity updating, see CdmaLteServiceStateTracker.
1105    }
1106
1107    /**
1108     * Check if GPRS got registered while voice is registered.
1109     *
1110     * @param dataRegState i.e. CGREG in GSM
1111     * @param voiceRegState i.e. CREG in GSM
1112     * @return false if device only register to voice but not gprs
1113     */
1114    private boolean isGprsConsistent(int dataRegState, int voiceRegState) {
1115        return !((voiceRegState == ServiceState.STATE_IN_SERVICE) &&
1116                (dataRegState != ServiceState.STATE_IN_SERVICE));
1117    }
1118
1119    /**
1120     * Returns a TimeZone object based only on parameters from the NITZ string.
1121     */
1122    private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
1123        TimeZone guess = findTimeZone(offset, dst, when);
1124        if (guess == null) {
1125            // Couldn't find a proper timezone.  Perhaps the DST data is wrong.
1126            guess = findTimeZone(offset, !dst, when);
1127        }
1128        if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID()));
1129        return guess;
1130    }
1131
1132    private TimeZone findTimeZone(int offset, boolean dst, long when) {
1133        int rawOffset = offset;
1134        if (dst) {
1135            rawOffset -= 3600000;
1136        }
1137        String[] zones = TimeZone.getAvailableIDs(rawOffset);
1138        TimeZone guess = null;
1139        Date d = new Date(when);
1140        for (String zone : zones) {
1141            TimeZone tz = TimeZone.getTimeZone(zone);
1142            if (tz.getOffset(when) == offset &&
1143                tz.inDaylightTime(d) == dst) {
1144                guess = tz;
1145                break;
1146            }
1147        }
1148
1149        return guess;
1150    }
1151
1152    private void queueNextSignalStrengthPoll() {
1153        if (mDontPollSignalStrength) {
1154            // The radio is telling us about signal strength changes
1155            // we don't have to ask it
1156            return;
1157        }
1158
1159        Message msg;
1160
1161        msg = obtainMessage();
1162        msg.what = EVENT_POLL_SIGNAL_STRENGTH;
1163
1164        long nextTime;
1165
1166        // TODO Don't poll signal strength if screen is off
1167        sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
1168    }
1169
1170    /**
1171     * Set restricted state based on the OnRestrictedStateChanged notification
1172     * If any voice or packet restricted state changes, trigger a UI
1173     * notification and notify registrants when sim is ready.
1174     *
1175     * @param ar an int value of RIL_RESTRICTED_STATE_*
1176     */
1177    private void onRestrictedStateChanged(AsyncResult ar) {
1178        RestrictedState newRs = new RestrictedState();
1179
1180        if (DBG) log("onRestrictedStateChanged: E rs "+ mRestrictedState);
1181
1182        if (ar.exception == null) {
1183            int[] ints = (int[])ar.result;
1184            int state = ints[0];
1185
1186            newRs.setCsEmergencyRestricted(
1187                    ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
1188                    ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
1189            //ignore the normal call and data restricted state before SIM READY
1190            if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY) {
1191                newRs.setCsNormalRestricted(
1192                        ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
1193                        ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
1194                newRs.setPsRestricted(
1195                        (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0);
1196            }
1197
1198            if (DBG) log("onRestrictedStateChanged: new rs "+ newRs);
1199
1200            if (!mRestrictedState.isPsRestricted() && newRs.isPsRestricted()) {
1201                mPsRestrictEnabledRegistrants.notifyRegistrants();
1202                setNotification(PS_ENABLED);
1203            } else if (mRestrictedState.isPsRestricted() && !newRs.isPsRestricted()) {
1204                mPsRestrictDisabledRegistrants.notifyRegistrants();
1205                setNotification(PS_DISABLED);
1206            }
1207
1208            /**
1209             * There are two kind of cs restriction, normal and emergency. So
1210             * there are 4 x 4 combinations in current and new restricted states
1211             * and we only need to notify when state is changed.
1212             */
1213            if (mRestrictedState.isCsRestricted()) {
1214                if (!newRs.isCsRestricted()) {
1215                    // remove all restriction
1216                    setNotification(CS_DISABLED);
1217                } else if (!newRs.isCsNormalRestricted()) {
1218                    // remove normal restriction
1219                    setNotification(CS_EMERGENCY_ENABLED);
1220                } else if (!newRs.isCsEmergencyRestricted()) {
1221                    // remove emergency restriction
1222                    setNotification(CS_NORMAL_ENABLED);
1223                }
1224            } else if (mRestrictedState.isCsEmergencyRestricted() &&
1225                    !mRestrictedState.isCsNormalRestricted()) {
1226                if (!newRs.isCsRestricted()) {
1227                    // remove all restriction
1228                    setNotification(CS_DISABLED);
1229                } else if (newRs.isCsRestricted()) {
1230                    // enable all restriction
1231                    setNotification(CS_ENABLED);
1232                } else if (newRs.isCsNormalRestricted()) {
1233                    // remove emergency restriction and enable normal restriction
1234                    setNotification(CS_NORMAL_ENABLED);
1235                }
1236            } else if (!mRestrictedState.isCsEmergencyRestricted() &&
1237                    mRestrictedState.isCsNormalRestricted()) {
1238                if (!newRs.isCsRestricted()) {
1239                    // remove all restriction
1240                    setNotification(CS_DISABLED);
1241                } else if (newRs.isCsRestricted()) {
1242                    // enable all restriction
1243                    setNotification(CS_ENABLED);
1244                } else if (newRs.isCsEmergencyRestricted()) {
1245                    // remove normal restriction and enable emergency restriction
1246                    setNotification(CS_EMERGENCY_ENABLED);
1247                }
1248            } else {
1249                if (newRs.isCsRestricted()) {
1250                    // enable all restriction
1251                    setNotification(CS_ENABLED);
1252                } else if (newRs.isCsEmergencyRestricted()) {
1253                    // enable emergency restriction
1254                    setNotification(CS_EMERGENCY_ENABLED);
1255                } else if (newRs.isCsNormalRestricted()) {
1256                    // enable normal restriction
1257                    setNotification(CS_NORMAL_ENABLED);
1258                }
1259            }
1260
1261            mRestrictedState = newRs;
1262        }
1263        log("onRestrictedStateChanged: X rs "+ mRestrictedState);
1264    }
1265
1266    /** code is registration state 0-5 from TS 27.007 7.2 */
1267    private int regCodeToServiceState(int code) {
1268        switch (code) {
1269            case 0:
1270            case 2: // 2 is "searching"
1271            case 3: // 3 is "registration denied"
1272            case 4: // 4 is "unknown" no vaild in current baseband
1273            case 10:// same as 0, but indicates that emergency call is possible.
1274            case 12:// same as 2, but indicates that emergency call is possible.
1275            case 13:// same as 3, but indicates that emergency call is possible.
1276            case 14:// same as 4, but indicates that emergency call is possible.
1277                return ServiceState.STATE_OUT_OF_SERVICE;
1278
1279            case 1:
1280                return ServiceState.STATE_IN_SERVICE;
1281
1282            case 5:
1283                // in service, roam
1284                return ServiceState.STATE_IN_SERVICE;
1285
1286            default:
1287                loge("regCodeToServiceState: unexpected service state " + code);
1288                return ServiceState.STATE_OUT_OF_SERVICE;
1289        }
1290    }
1291
1292
1293    /**
1294     * code is registration state 0-5 from TS 27.007 7.2
1295     * returns true if registered roam, false otherwise
1296     */
1297    private boolean regCodeIsRoaming (int code) {
1298        return ServiceState.RIL_REG_STATE_ROAMING == code;
1299    }
1300
1301    /**
1302     * Set roaming state if operator mcc is the same as sim mcc
1303     * and ons is different from spn
1304     *
1305     * @param s ServiceState hold current ons
1306     * @return true if same operator
1307     */
1308    private boolean isSameNamedOperators(ServiceState s) {
1309        String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty");
1310
1311        String onsl = s.getOperatorAlphaLong();
1312        String onss = s.getOperatorAlphaShort();
1313
1314        boolean equalsOnsl = onsl != null && spn.equals(onsl);
1315        boolean equalsOnss = onss != null && spn.equals(onss);
1316
1317        return currentMccEqualsSimMcc(s) && (equalsOnsl || equalsOnss);
1318    }
1319
1320    /**
1321     * Compare SIM MCC with Operator MCC
1322     *
1323     * @param s ServiceState hold current ons
1324     * @return true if both are same
1325     */
1326    private boolean currentMccEqualsSimMcc(ServiceState s) {
1327        String simNumeric = SystemProperties.get(
1328                TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
1329        String operatorNumeric = s.getOperatorNumeric();
1330        boolean equalsMcc = true;
1331
1332        try {
1333            equalsMcc = simNumeric.substring(0, 3).
1334                    equals(operatorNumeric.substring(0, 3));
1335        } catch (Exception e){
1336        }
1337        return equalsMcc;
1338    }
1339
1340    /**
1341     * Do not set roaming state in case of oprators considered non-roaming.
1342     *
1343     + Can use mcc or mcc+mnc as item of config_operatorConsideredNonRoaming.
1344     * For example, 302 or 21407. If mcc or mcc+mnc match with operator,
1345     * don't set roaming state.
1346     *
1347     * @param s ServiceState hold current ons
1348     * @return false for roaming state set
1349     */
1350    private boolean isOperatorConsideredNonRoaming(ServiceState s) {
1351        String operatorNumeric = s.getOperatorNumeric();
1352        String[] numericArray = mPhone.getContext().getResources().getStringArray(
1353                    com.android.internal.R.array.config_operatorConsideredNonRoaming);
1354
1355        if (numericArray.length == 0 || operatorNumeric == null)
1356            return false;
1357
1358        for (String numeric : numericArray) {
1359            if (operatorNumeric.startsWith(numeric))
1360                return true;
1361            else
1362                return false;
1363        }
1364        return false;
1365    }
1366
1367    /**
1368     * @return The current GPRS state. IN_SERVICE is the same as "attached"
1369     * and OUT_OF_SERVICE is the same as detached.
1370     */
1371    @Override
1372    public int getCurrentDataConnectionState() {
1373        return mSS.getDataRegState();
1374    }
1375
1376    /**
1377     * @return true if phone is camping on a technology (eg UMTS)
1378     * that could support voice and data simultaneously.
1379     */
1380    @Override
1381    public boolean isConcurrentVoiceAndDataAllowed() {
1382        return (mSS.getRilVoiceRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
1383    }
1384
1385    /**
1386     * @return the current cell location information. Prefer Gsm location
1387     * information if available otherwise return LTE location information
1388     */
1389    public CellLocation getCellLocation() {
1390        if ((mCellLoc.getLac() >= 0) && (mCellLoc.getCid() >= 0)) {
1391            if (DBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc);
1392            return mCellLoc;
1393        } else {
1394            List<CellInfo> result = getAllCellInfo();
1395            if (result != null) {
1396                // A hack to allow tunneling of LTE information via GsmCellLocation
1397                // so that older Network Location Providers can return some information
1398                // on LTE only networks, see bug 9228974.
1399                //
1400                // We'll search the return CellInfo array preferring GSM/WCDMA
1401                // data, but if there is none we'll tunnel the first LTE information
1402                // in the list.
1403                //
1404                // The tunnel'd LTE information is returned as follows:
1405                //   LAC = TAC field
1406                //   CID = CI field
1407                //   PSC = 0.
1408                GsmCellLocation cellLocOther = new GsmCellLocation();
1409                for (CellInfo ci : result) {
1410                    if (ci instanceof CellInfoGsm) {
1411                        CellInfoGsm cellInfoGsm = (CellInfoGsm)ci;
1412                        CellIdentityGsm cellIdentityGsm = cellInfoGsm.getCellIdentity();
1413                        cellLocOther.setLacAndCid(cellIdentityGsm.getLac(),
1414                                cellIdentityGsm.getCid());
1415                        cellLocOther.setPsc(cellIdentityGsm.getPsc());
1416                        if (DBG) log("getCellLocation(): X ret GSM info=" + cellLocOther);
1417                        return cellLocOther;
1418                    } else if (ci instanceof CellInfoWcdma) {
1419                        CellInfoWcdma cellInfoWcdma = (CellInfoWcdma)ci;
1420                        CellIdentityWcdma cellIdentityWcdma = cellInfoWcdma.getCellIdentity();
1421                        cellLocOther.setLacAndCid(cellIdentityWcdma.getLac(),
1422                                cellIdentityWcdma.getCid());
1423                        cellLocOther.setPsc(cellIdentityWcdma.getPsc());
1424                        if (DBG) log("getCellLocation(): X ret WCDMA info=" + cellLocOther);
1425                        return cellLocOther;
1426                    } else if ((ci instanceof CellInfoLte) &&
1427                            ((cellLocOther.getLac() < 0) || (cellLocOther.getCid() < 0))) {
1428                        // We'll return the first good LTE info we get if there is no better answer
1429                        CellInfoLte cellInfoLte = (CellInfoLte)ci;
1430                        CellIdentityLte cellIdentityLte = cellInfoLte.getCellIdentity();
1431                        if ((cellIdentityLte.getTac() != Integer.MAX_VALUE)
1432                                && (cellIdentityLte.getCi() != Integer.MAX_VALUE)) {
1433                            cellLocOther.setLacAndCid(cellIdentityLte.getTac(),
1434                                    cellIdentityLte.getCi());
1435                            cellLocOther.setPsc(0);
1436                            if (DBG) {
1437                                log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther);
1438                            }
1439                        }
1440                    }
1441                }
1442                if (DBG) {
1443                    log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther);
1444                }
1445                return cellLocOther;
1446            } else {
1447                if (DBG) {
1448                    log("getCellLocation(): X empty mCellLoc and CellInfo mCellLoc=" + mCellLoc);
1449                }
1450                return mCellLoc;
1451            }
1452        }
1453    }
1454
1455    /**
1456     * nitzReceiveTime is time_t that the NITZ time was posted
1457     */
1458    private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {
1459        // "yy/mm/dd,hh:mm:ss(+/-)tz"
1460        // tz is in number of quarter-hours
1461
1462        long start = SystemClock.elapsedRealtime();
1463        if (DBG) {log("NITZ: " + nitz + "," + nitzReceiveTime +
1464                        " start=" + start + " delay=" + (start - nitzReceiveTime));
1465        }
1466
1467        try {
1468            /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
1469             * offset as well (which we won't worry about until later) */
1470            Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
1471
1472            c.clear();
1473            c.set(Calendar.DST_OFFSET, 0);
1474
1475            String[] nitzSubs = nitz.split("[/:,+-]");
1476
1477            int year = 2000 + Integer.parseInt(nitzSubs[0]);
1478            c.set(Calendar.YEAR, year);
1479
1480            // month is 0 based!
1481            int month = Integer.parseInt(nitzSubs[1]) - 1;
1482            c.set(Calendar.MONTH, month);
1483
1484            int date = Integer.parseInt(nitzSubs[2]);
1485            c.set(Calendar.DATE, date);
1486
1487            int hour = Integer.parseInt(nitzSubs[3]);
1488            c.set(Calendar.HOUR, hour);
1489
1490            int minute = Integer.parseInt(nitzSubs[4]);
1491            c.set(Calendar.MINUTE, minute);
1492
1493            int second = Integer.parseInt(nitzSubs[5]);
1494            c.set(Calendar.SECOND, second);
1495
1496            boolean sign = (nitz.indexOf('-') == -1);
1497
1498            int tzOffset = Integer.parseInt(nitzSubs[6]);
1499
1500            int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
1501                                              : 0;
1502
1503            // The zone offset received from NITZ is for current local time,
1504            // so DST correction is already applied.  Don't add it again.
1505            //
1506            // tzOffset += dst * 4;
1507            //
1508            // We could unapply it if we wanted the raw offset.
1509
1510            tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
1511
1512            TimeZone    zone = null;
1513
1514            // As a special extension, the Android emulator appends the name of
1515            // the host computer's timezone to the nitz string. this is zoneinfo
1516            // timezone name of the form Area!Location or Area!Location!SubLocation
1517            // so we need to convert the ! into /
1518            if (nitzSubs.length >= 9) {
1519                String  tzname = nitzSubs[8].replace('!','/');
1520                zone = TimeZone.getTimeZone( tzname );
1521            }
1522
1523            String iso = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
1524
1525            if (zone == null) {
1526
1527                if (mGotCountryCode) {
1528                    if (iso != null && iso.length() > 0) {
1529                        zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
1530                                c.getTimeInMillis(),
1531                                iso);
1532                    } else {
1533                        // We don't have a valid iso country code.  This is
1534                        // most likely because we're on a test network that's
1535                        // using a bogus MCC (eg, "001"), so get a TimeZone
1536                        // based only on the NITZ parameters.
1537                        zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
1538                    }
1539                }
1540            }
1541
1542            if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){
1543                // We got the time before the country or the zone has changed
1544                // so we don't know how to identify the DST rules yet.  Save
1545                // the information and hope to fix it up later.
1546
1547                mNeedFixZoneAfterNitz = true;
1548                mZoneOffset  = tzOffset;
1549                mZoneDst     = dst != 0;
1550                mZoneTime    = c.getTimeInMillis();
1551            }
1552
1553            if (zone != null) {
1554                if (getAutoTimeZone()) {
1555                    setAndBroadcastNetworkSetTimeZone(zone.getID());
1556                }
1557                saveNitzTimeZone(zone.getID());
1558            }
1559
1560            String ignore = SystemProperties.get("gsm.ignore-nitz");
1561            if (ignore != null && ignore.equals("yes")) {
1562                log("NITZ: Not setting clock because gsm.ignore-nitz is set");
1563                return;
1564            }
1565
1566            try {
1567                mWakeLock.acquire();
1568
1569                if (getAutoTime()) {
1570                    long millisSinceNitzReceived
1571                            = SystemClock.elapsedRealtime() - nitzReceiveTime;
1572
1573                    if (millisSinceNitzReceived < 0) {
1574                        // Sanity check: something is wrong
1575                        if (DBG) {
1576                            log("NITZ: not setting time, clock has rolled "
1577                                            + "backwards since NITZ time was received, "
1578                                            + nitz);
1579                        }
1580                        return;
1581                    }
1582
1583                    if (millisSinceNitzReceived > Integer.MAX_VALUE) {
1584                        // If the time is this far off, something is wrong > 24 days!
1585                        if (DBG) {
1586                            log("NITZ: not setting time, processing has taken "
1587                                        + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
1588                                        + " days");
1589                        }
1590                        return;
1591                    }
1592
1593                    // Note: with range checks above, cast to int is safe
1594                    c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
1595
1596                    if (DBG) {
1597                        log("NITZ: Setting time of day to " + c.getTime()
1598                            + " NITZ receive delay(ms): " + millisSinceNitzReceived
1599                            + " gained(ms): "
1600                            + (c.getTimeInMillis() - System.currentTimeMillis())
1601                            + " from " + nitz);
1602                    }
1603
1604                    setAndBroadcastNetworkSetTime(c.getTimeInMillis());
1605                    Rlog.i(LOG_TAG, "NITZ: after Setting time of day");
1606                }
1607                SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
1608                saveNitzTime(c.getTimeInMillis());
1609                if (VDBG) {
1610                    long end = SystemClock.elapsedRealtime();
1611                    log("NITZ: end=" + end + " dur=" + (end - start));
1612                }
1613                mNitzUpdatedTime = true;
1614            } finally {
1615                mWakeLock.release();
1616            }
1617        } catch (RuntimeException ex) {
1618            loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
1619        }
1620    }
1621
1622    private boolean getAutoTime() {
1623        try {
1624            return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1625                    Settings.Global.AUTO_TIME) > 0;
1626        } catch (SettingNotFoundException snfe) {
1627            return true;
1628        }
1629    }
1630
1631    private boolean getAutoTimeZone() {
1632        try {
1633            return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1634                    Settings.Global.AUTO_TIME_ZONE) > 0;
1635        } catch (SettingNotFoundException snfe) {
1636            return true;
1637        }
1638    }
1639
1640    private void saveNitzTimeZone(String zoneId) {
1641        mSavedTimeZone = zoneId;
1642    }
1643
1644    private void saveNitzTime(long time) {
1645        mSavedTime = time;
1646        mSavedAtTime = SystemClock.elapsedRealtime();
1647    }
1648
1649    /**
1650     * Set the timezone and send out a sticky broadcast so the system can
1651     * determine if the timezone was set by the carrier.
1652     *
1653     * @param zoneId timezone set by carrier
1654     */
1655    private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
1656        if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId);
1657        AlarmManager alarm =
1658            (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
1659        alarm.setTimeZone(zoneId);
1660        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
1661        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1662        intent.putExtra("time-zone", zoneId);
1663        mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1664        if (DBG) {
1665            log("setAndBroadcastNetworkSetTimeZone: call alarm.setTimeZone and broadcast zoneId=" +
1666                zoneId);
1667        }
1668    }
1669
1670    /**
1671     * Set the time and Send out a sticky broadcast so the system can determine
1672     * if the time was set by the carrier.
1673     *
1674     * @param time time set by network
1675     */
1676    private void setAndBroadcastNetworkSetTime(long time) {
1677        if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
1678        SystemClock.setCurrentTimeMillis(time);
1679        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
1680        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1681        intent.putExtra("time", time);
1682        mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1683    }
1684
1685    private void revertToNitzTime() {
1686        if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1687                Settings.Global.AUTO_TIME, 0) == 0) {
1688            return;
1689        }
1690        if (DBG) {
1691            log("Reverting to NITZ Time: mSavedTime=" + mSavedTime
1692                + " mSavedAtTime=" + mSavedAtTime);
1693        }
1694        if (mSavedTime != 0 && mSavedAtTime != 0) {
1695            setAndBroadcastNetworkSetTime(mSavedTime
1696                    + (SystemClock.elapsedRealtime() - mSavedAtTime));
1697        }
1698    }
1699
1700    private void revertToNitzTimeZone() {
1701        if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1702                Settings.Global.AUTO_TIME_ZONE, 0) == 0) {
1703            return;
1704        }
1705        if (DBG) log("Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);
1706        if (mSavedTimeZone != null) {
1707            setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
1708        }
1709    }
1710
1711    /**
1712     * Post a notification to NotificationManager for restricted state
1713     *
1714     * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE
1715     */
1716    private void setNotification(int notifyType) {
1717
1718        if (DBG) log("setNotification: create notification " + notifyType);
1719        Context context = mPhone.getContext();
1720
1721        mNotification = new Notification();
1722        mNotification.when = System.currentTimeMillis();
1723        mNotification.flags = Notification.FLAG_AUTO_CANCEL;
1724        mNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
1725        Intent intent = new Intent();
1726        mNotification.contentIntent = PendingIntent
1727        .getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
1728
1729        CharSequence details = "";
1730        CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle);
1731        int notificationId = CS_NOTIFICATION;
1732
1733        switch (notifyType) {
1734        case PS_ENABLED:
1735            notificationId = PS_NOTIFICATION;
1736            details = context.getText(com.android.internal.R.string.RestrictedOnData);
1737            break;
1738        case PS_DISABLED:
1739            notificationId = PS_NOTIFICATION;
1740            break;
1741        case CS_ENABLED:
1742            details = context.getText(com.android.internal.R.string.RestrictedOnAllVoice);
1743            break;
1744        case CS_NORMAL_ENABLED:
1745            details = context.getText(com.android.internal.R.string.RestrictedOnNormal);
1746            break;
1747        case CS_EMERGENCY_ENABLED:
1748            details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);
1749            break;
1750        case CS_DISABLED:
1751            // do nothing and cancel the notification later
1752            break;
1753        }
1754
1755        if (DBG) log("setNotification: put notification " + title + " / " +details);
1756        mNotification.tickerText = title;
1757        mNotification.setLatestEventInfo(context, title, details,
1758                mNotification.contentIntent);
1759
1760        NotificationManager notificationManager = (NotificationManager)
1761            context.getSystemService(Context.NOTIFICATION_SERVICE);
1762
1763        if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) {
1764            // cancel previous post notification
1765            notificationManager.cancel(notificationId);
1766        } else {
1767            // update restricted state notification
1768            notificationManager.notify(notificationId, mNotification);
1769        }
1770    }
1771
1772    @Override
1773    protected void onUpdateIccAvailability() {
1774        if (mUiccController == null ) {
1775            return;
1776        }
1777
1778        UiccCardApplication newUiccApplication =
1779                mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);
1780
1781        if (mUiccApplcation != newUiccApplication) {
1782            if (mUiccApplcation != null) {
1783                log("Removing stale icc objects.");
1784                mUiccApplcation.unregisterForReady(this);
1785                if (mIccRecords != null) {
1786                    mIccRecords.unregisterForRecordsLoaded(this);
1787                }
1788                mIccRecords = null;
1789                mUiccApplcation = null;
1790            }
1791            if (newUiccApplication != null) {
1792                log("New card found");
1793                mUiccApplcation = newUiccApplication;
1794                mIccRecords = mUiccApplcation.getIccRecords();
1795                mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);
1796                if (mIccRecords != null) {
1797                    mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
1798                }
1799            }
1800        }
1801    }
1802    @Override
1803    protected void log(String s) {
1804        Rlog.d(LOG_TAG, "[GsmSST] " + s);
1805    }
1806
1807    @Override
1808    protected void loge(String s) {
1809        Rlog.e(LOG_TAG, "[GsmSST] " + s);
1810    }
1811
1812    @Override
1813    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1814        pw.println("GsmServiceStateTracker extends:");
1815        super.dump(fd, pw, args);
1816        pw.println(" mPhone=" + mPhone);
1817        pw.println(" mSS=" + mSS);
1818        pw.println(" mNewSS=" + mNewSS);
1819        pw.println(" mCellLoc=" + mCellLoc);
1820        pw.println(" mNewCellLoc=" + mNewCellLoc);
1821        pw.println(" mPreferredNetworkType=" + mPreferredNetworkType);
1822        pw.println(" mMaxDataCalls=" + mMaxDataCalls);
1823        pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls);
1824        pw.println(" mReasonDataDenied=" + mReasonDataDenied);
1825        pw.println(" mNewReasonDataDenied=" + mNewReasonDataDenied);
1826        pw.println(" mGsmRoaming=" + mGsmRoaming);
1827        pw.println(" mDataRoaming=" + mDataRoaming);
1828        pw.println(" mEmergencyOnly=" + mEmergencyOnly);
1829        pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz);
1830        pw.println(" mZoneOffset=" + mZoneOffset);
1831        pw.println(" mZoneDst=" + mZoneDst);
1832        pw.println(" mZoneTime=" + mZoneTime);
1833        pw.println(" mGotCountryCode=" + mGotCountryCode);
1834        pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime);
1835        pw.println(" mSavedTimeZone=" + mSavedTimeZone);
1836        pw.println(" mSavedTime=" + mSavedTime);
1837        pw.println(" mSavedAtTime=" + mSavedAtTime);
1838        pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
1839        pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
1840        pw.println(" mNotification=" + mNotification);
1841        pw.println(" mWakeLock=" + mWakeLock);
1842        pw.println(" mCurSpn=" + mCurSpn);
1843        pw.println(" mCurShowSpn=" + mCurShowSpn);
1844        pw.println(" mCurPlmn=" + mCurPlmn);
1845        pw.println(" mCurShowPlmn=" + mCurShowPlmn);
1846    }
1847}
1848