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