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