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