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