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