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