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