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