Home | History | Annotate | Download | only in telephony
      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;
     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.SharedPreferences;
     29 import android.content.res.Resources;
     30 import android.database.ContentObserver;
     31 import android.os.AsyncResult;
     32 import android.os.BaseBundle;
     33 import android.os.Build;
     34 import android.os.Handler;
     35 import android.os.Looper;
     36 import android.os.Message;
     37 import android.os.PersistableBundle;
     38 import android.os.PowerManager;
     39 import android.os.Registrant;
     40 import android.os.RegistrantList;
     41 import android.os.RemoteException;
     42 import android.os.ServiceManager;
     43 import android.os.SystemClock;
     44 import android.os.SystemProperties;
     45 import android.os.UserHandle;
     46 import android.preference.PreferenceManager;
     47 import android.provider.Settings;
     48 import android.telephony.CarrierConfigManager;
     49 import android.telephony.CellIdentityGsm;
     50 import android.telephony.CellIdentityLte;
     51 import android.telephony.CellIdentityWcdma;
     52 import android.telephony.CellInfo;
     53 import android.telephony.CellInfoCdma;
     54 import android.telephony.CellInfoGsm;
     55 import android.telephony.CellInfoLte;
     56 import android.telephony.CellInfoWcdma;
     57 import android.telephony.CellLocation;
     58 import android.telephony.CellSignalStrengthLte;
     59 import android.telephony.Rlog;
     60 import android.telephony.ServiceState;
     61 import android.telephony.SignalStrength;
     62 import android.telephony.SubscriptionManager;
     63 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
     64 import android.telephony.TelephonyManager;
     65 import android.telephony.cdma.CdmaCellLocation;
     66 import android.telephony.gsm.GsmCellLocation;
     67 import android.text.TextUtils;
     68 import android.util.EventLog;
     69 import android.util.Pair;
     70 import android.util.TimeUtils;
     71 
     72 import java.io.FileDescriptor;
     73 import java.io.PrintWriter;
     74 import java.util.ArrayList;
     75 import java.util.Arrays;
     76 import java.util.Calendar;
     77 import java.util.Date;
     78 import java.util.List;
     79 import java.util.TimeZone;
     80 import java.util.concurrent.atomic.AtomicInteger;
     81 
     82 import com.android.internal.annotations.VisibleForTesting;
     83 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
     84 import com.android.internal.telephony.cdma.EriInfo;
     85 import com.android.internal.telephony.dataconnection.DcTracker;
     86 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
     87 import com.android.internal.telephony.uicc.IccRecords;
     88 import com.android.internal.telephony.uicc.RuimRecords;
     89 import com.android.internal.telephony.uicc.SIMRecords;
     90 import com.android.internal.telephony.uicc.UiccCardApplication;
     91 import com.android.internal.telephony.uicc.UiccController;
     92 
     93 /**
     94  * {@hide}
     95  */
     96 public class ServiceStateTracker extends Handler {
     97     private static final String LOG_TAG = "SST";
     98     private static final boolean DBG = true;
     99     private static final boolean VDBG = false;  // STOPSHIP if true
    100 
    101     private static final String PROP_FORCE_ROAMING = "telephony.test.forceRoaming";
    102 
    103     private CommandsInterface mCi;
    104     private UiccController mUiccController = null;
    105     private UiccCardApplication mUiccApplcation = null;
    106     private IccRecords mIccRecords = null;
    107     private TelephonyEventLog mEventLog;
    108 
    109     private boolean mVoiceCapable;
    110 
    111     public ServiceState mSS;
    112     private ServiceState mNewSS;
    113 
    114     private static final long LAST_CELL_INFO_LIST_MAX_AGE_MS = 2000;
    115     private long mLastCellInfoListTime;
    116     private List<CellInfo> mLastCellInfoList = null;
    117 
    118     private SignalStrength mSignalStrength;
    119 
    120     // TODO - this should not be public, right now used externally GsmConnetion.
    121     public RestrictedState mRestrictedState;
    122 
    123     /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
    124     static public final int OTASP_UNINITIALIZED = 0;
    125     static public final int OTASP_UNKNOWN = 1;
    126     static public final int OTASP_NEEDED = 2;
    127     static public final int OTASP_NOT_NEEDED = 3;
    128     /**
    129      * OtaUtil has conflict enum 4: OtaUtils.OTASP_FAILURE_SPC_RETRIES
    130      */
    131     static public final int OTASP_SIM_UNPROVISIONED = 5;
    132 
    133     /**
    134      * A unique identifier to track requests associated with a poll
    135      * and ignore stale responses.  The value is a count-down of
    136      * expected responses in this pollingContext.
    137      */
    138     private int[] mPollingContext;
    139     private boolean mDesiredPowerState;
    140 
    141     /**
    142      * By default, strength polling is enabled.  However, if we're
    143      * getting unsolicited signal strength updates from the radio, set
    144      * value to true and don't bother polling any more.
    145      */
    146     private boolean mDontPollSignalStrength = false;
    147 
    148     private RegistrantList mVoiceRoamingOnRegistrants = new RegistrantList();
    149     private RegistrantList mVoiceRoamingOffRegistrants = new RegistrantList();
    150     private RegistrantList mDataRoamingOnRegistrants = new RegistrantList();
    151     private RegistrantList mDataRoamingOffRegistrants = new RegistrantList();
    152     protected RegistrantList mAttachedRegistrants = new RegistrantList();
    153     protected RegistrantList mDetachedRegistrants = new RegistrantList();
    154     private RegistrantList mDataRegStateOrRatChangedRegistrants = new RegistrantList();
    155     private RegistrantList mNetworkAttachedRegistrants = new RegistrantList();
    156     private RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList();
    157     private RegistrantList mPsRestrictDisabledRegistrants = new RegistrantList();
    158 
    159     /* Radio power off pending flag and tag counter */
    160     private boolean mPendingRadioPowerOffAfterDataOff = false;
    161     private int mPendingRadioPowerOffAfterDataOffTag = 0;
    162 
    163     /** Signal strength poll rate. */
    164     private static final int POLL_PERIOD_MILLIS = 20 * 1000;
    165 
    166     /** Waiting period before recheck gprs and voice registration. */
    167     public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
    168 
    169     /** GSM events */
    170     protected static final int EVENT_RADIO_STATE_CHANGED               = 1;
    171     protected static final int EVENT_NETWORK_STATE_CHANGED             = 2;
    172     protected static final int EVENT_GET_SIGNAL_STRENGTH               = 3;
    173     protected static final int EVENT_POLL_STATE_REGISTRATION           = 4;
    174     protected static final int EVENT_POLL_STATE_GPRS                   = 5;
    175     protected static final int EVENT_POLL_STATE_OPERATOR               = 6;
    176     protected static final int EVENT_POLL_SIGNAL_STRENGTH              = 10;
    177     protected static final int EVENT_NITZ_TIME                         = 11;
    178     protected static final int EVENT_SIGNAL_STRENGTH_UPDATE            = 12;
    179     protected static final int EVENT_RADIO_AVAILABLE                   = 13;
    180     protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14;
    181     protected static final int EVENT_GET_LOC_DONE                      = 15;
    182     protected static final int EVENT_SIM_RECORDS_LOADED                = 16;
    183     protected static final int EVENT_SIM_READY                         = 17;
    184     protected static final int EVENT_LOCATION_UPDATES_ENABLED          = 18;
    185     protected static final int EVENT_GET_PREFERRED_NETWORK_TYPE        = 19;
    186     protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE        = 20;
    187     protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE      = 21;
    188     protected static final int EVENT_CHECK_REPORT_GPRS                 = 22;
    189     protected static final int EVENT_RESTRICTED_STATE_CHANGED          = 23;
    190 
    191     /** CDMA events */
    192     protected static final int EVENT_RUIM_READY                        = 26;
    193     protected static final int EVENT_RUIM_RECORDS_LOADED               = 27;
    194     protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION      = 34;
    195     protected static final int EVENT_NV_READY                          = 35;
    196     protected static final int EVENT_ERI_FILE_LOADED                   = 36;
    197     protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE       = 37;
    198     protected static final int EVENT_SET_RADIO_POWER_OFF               = 38;
    199     protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED  = 39;
    200     protected static final int EVENT_CDMA_PRL_VERSION_CHANGED          = 40;
    201 
    202     protected static final int EVENT_RADIO_ON                          = 41;
    203     public    static final int EVENT_ICC_CHANGED                       = 42;
    204     protected static final int EVENT_GET_CELL_INFO_LIST                = 43;
    205     protected static final int EVENT_UNSOL_CELL_INFO_LIST              = 44;
    206     protected static final int EVENT_CHANGE_IMS_STATE                  = 45;
    207     protected static final int EVENT_IMS_STATE_CHANGED                 = 46;
    208     protected static final int EVENT_IMS_STATE_DONE                    = 47;
    209     protected static final int EVENT_IMS_CAPABILITY_CHANGED            = 48;
    210     protected static final int EVENT_ALL_DATA_DISCONNECTED             = 49;
    211     protected static final int EVENT_PHONE_TYPE_SWITCHED               = 50;
    212 
    213     protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
    214 
    215     /**
    216      * List of ISO codes for countries that can have an offset of
    217      * GMT+0 when not in daylight savings time.  This ignores some
    218      * small places such as the Canary Islands (Spain) and
    219      * Danmarkshavn (Denmark).  The list must be sorted by code.
    220     */
    221     protected static final String[] GMT_COUNTRY_CODES = {
    222         "bf", // Burkina Faso
    223         "ci", // Cote d'Ivoire
    224         "eh", // Western Sahara
    225         "fo", // Faroe Islands, Denmark
    226         "gb", // United Kingdom of Great Britain and Northern Ireland
    227         "gh", // Ghana
    228         "gm", // Gambia
    229         "gn", // Guinea
    230         "gw", // Guinea Bissau
    231         "ie", // Ireland
    232         "lr", // Liberia
    233         "is", // Iceland
    234         "ma", // Morocco
    235         "ml", // Mali
    236         "mr", // Mauritania
    237         "pt", // Portugal
    238         "sl", // Sierra Leone
    239         "sn", // Senegal
    240         "st", // Sao Tome and Principe
    241         "tg", // Togo
    242     };
    243 
    244     private class CellInfoResult {
    245         List<CellInfo> list;
    246         Object lockObj = new Object();
    247     }
    248 
    249     /** Reason for registration denial. */
    250     protected static final String REGISTRATION_DENIED_GEN  = "General";
    251     protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure";
    252 
    253     private boolean mImsRegistrationOnOff = false;
    254     private boolean mAlarmSwitch = false;
    255     /** Radio is disabled by carrier. Radio power will not be override if this field is set */
    256     private boolean mRadioDisabledByCarrier = false;
    257     private PendingIntent mRadioOffIntent = null;
    258     private static final String ACTION_RADIO_OFF = "android.intent.action.ACTION_RADIO_OFF";
    259     private boolean mPowerOffDelayNeed = true;
    260     private boolean mDeviceShuttingDown = false;
    261     /** Keep track of SPN display rules, so we only broadcast intent if something changes. */
    262     private boolean mSpnUpdatePending = false;
    263     private String mCurSpn = null;
    264     private String mCurDataSpn = null;
    265     private String mCurPlmn = null;
    266     private boolean mCurShowPlmn = false;
    267     private boolean mCurShowSpn = false;
    268     private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    269 
    270     private boolean mImsRegistered = false;
    271 
    272     private SubscriptionManager mSubscriptionManager;
    273     private SubscriptionController mSubscriptionController;
    274     private final SstSubscriptionsChangedListener mOnSubscriptionsChangedListener =
    275         new SstSubscriptionsChangedListener();
    276 
    277 
    278     private final RatRatcheter mRatRatcheter;
    279 
    280     private class SstSubscriptionsChangedListener extends OnSubscriptionsChangedListener {
    281         public final AtomicInteger mPreviousSubId =
    282                 new AtomicInteger(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
    283 
    284         /**
    285          * Callback invoked when there is any change to any SubscriptionInfo. Typically
    286          * this method would invoke {@link SubscriptionManager#getActiveSubscriptionInfoList}
    287          */
    288         @Override
    289         public void onSubscriptionsChanged() {
    290             if (DBG) log("SubscriptionListener.onSubscriptionInfoChanged");
    291             // Set the network type, in case the radio does not restore it.
    292             int subId = mPhone.getSubId();
    293             if (mPreviousSubId.getAndSet(subId) != subId) {
    294                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
    295                     Context context = mPhone.getContext();
    296 
    297                     mPhone.notifyPhoneStateChanged();
    298                     mPhone.notifyCallForwardingIndicator();
    299 
    300                     boolean restoreSelection = !context.getResources().getBoolean(
    301                             com.android.internal.R.bool.skip_restoring_network_selection);
    302                     mPhone.sendSubscriptionSettings(restoreSelection);
    303 
    304                     mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
    305                             ServiceState.rilRadioTechnologyToString(
    306                                     mSS.getRilDataRadioTechnology()));
    307 
    308                     if (mSpnUpdatePending) {
    309                         mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), mCurShowPlmn,
    310                                 mCurPlmn, mCurShowSpn, mCurSpn);
    311                         mSpnUpdatePending = false;
    312                     }
    313 
    314                     // Remove old network selection sharedPreferences since SP key names are now
    315                     // changed to include subId. This will be done only once when upgrading from an
    316                     // older build that did not include subId in the names.
    317                     SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
    318                             context);
    319                     String oldNetworkSelection = sp.getString(
    320                             Phone.NETWORK_SELECTION_KEY, "");
    321                     String oldNetworkSelectionName = sp.getString(
    322                             Phone.NETWORK_SELECTION_NAME_KEY, "");
    323                     String oldNetworkSelectionShort = sp.getString(
    324                             Phone.NETWORK_SELECTION_SHORT_KEY, "");
    325                     if (!TextUtils.isEmpty(oldNetworkSelection) ||
    326                             !TextUtils.isEmpty(oldNetworkSelectionName) ||
    327                             !TextUtils.isEmpty(oldNetworkSelectionShort)) {
    328                         SharedPreferences.Editor editor = sp.edit();
    329                         editor.putString(Phone.NETWORK_SELECTION_KEY + subId,
    330                                 oldNetworkSelection);
    331                         editor.putString(Phone.NETWORK_SELECTION_NAME_KEY + subId,
    332                                 oldNetworkSelectionName);
    333                         editor.putString(Phone.NETWORK_SELECTION_SHORT_KEY + subId,
    334                                 oldNetworkSelectionShort);
    335                         editor.remove(Phone.NETWORK_SELECTION_KEY);
    336                         editor.remove(Phone.NETWORK_SELECTION_NAME_KEY);
    337                         editor.remove(Phone.NETWORK_SELECTION_SHORT_KEY);
    338                         editor.commit();
    339                     }
    340 
    341                     // Once sub id becomes valid, we need to update the service provider name
    342                     // displayed on the UI again. The old SPN update intents sent to
    343                     // MobileSignalController earlier were actually ignored due to invalid sub id.
    344                     updateSpnDisplay();
    345                 }
    346                 // update voicemail count and notify message waiting changed
    347                 mPhone.updateVoiceMail();
    348             }
    349         }
    350     };
    351 
    352     //Common
    353     private GsmCdmaPhone mPhone;
    354     public CellLocation mCellLoc;
    355     private CellLocation mNewCellLoc;
    356     public static final int MS_PER_HOUR = 60 * 60 * 1000;
    357     /* Time stamp after 19 January 2038 is not supported under 32 bit */
    358     private static final int MAX_NITZ_YEAR = 2037;
    359     /**
    360      * Sometimes we get the NITZ time before we know what country we
    361      * are in. Keep the time zone information from the NITZ string so
    362      * we can fix the time zone once know the country.
    363      */
    364     private boolean mNeedFixZoneAfterNitz = false;
    365     private int mZoneOffset;
    366     private boolean mZoneDst;
    367     private long mZoneTime;
    368     private boolean mGotCountryCode = false;
    369     private String mSavedTimeZone;
    370     private long mSavedTime;
    371     private long mSavedAtTime;
    372     /** Wake lock used while setting time of day. */
    373     private PowerManager.WakeLock mWakeLock;
    374     public static final String WAKELOCK_TAG = "ServiceStateTracker";
    375     private ContentResolver mCr;
    376     private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
    377         @Override
    378         public void onChange(boolean selfChange) {
    379             Rlog.i(LOG_TAG, "Auto time state changed");
    380             revertToNitzTime();
    381         }
    382     };
    383 
    384     private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
    385         @Override
    386         public void onChange(boolean selfChange) {
    387             Rlog.i(LOG_TAG, "Auto time zone state changed");
    388             revertToNitzTimeZone();
    389         }
    390     };
    391 
    392     //GSM
    393     private int mPreferredNetworkType;
    394     private int mMaxDataCalls = 1;
    395     private int mNewMaxDataCalls = 1;
    396     private int mReasonDataDenied = -1;
    397     private int mNewReasonDataDenied = -1;
    398     /**
    399      * GSM roaming status solely based on TS 27.007 7.2 CREG. Only used by
    400      * handlePollStateResult to store CREG roaming result.
    401      */
    402     private boolean mGsmRoaming = false;
    403     /**
    404      * Data roaming status solely based on TS 27.007 10.1.19 CGREG. Only used by
    405      * handlePollStateResult to store CGREG roaming result.
    406      */
    407     private boolean mDataRoaming = false;
    408     /**
    409      * Mark when service state is in emergency call only mode
    410      */
    411     private boolean mEmergencyOnly = false;
    412     /** Boolean is true is setTimeFromNITZString was called */
    413     private boolean mNitzUpdatedTime = false;
    414     /** Started the recheck process after finding gprs should registered but not. */
    415     private boolean mStartedGprsRegCheck;
    416     /** Already sent the event-log for no gprs register. */
    417     private boolean mReportedGprsNoReg;
    418     /**
    419      * The Notification object given to the NotificationManager.
    420      */
    421     private Notification mNotification;
    422     /** Notification type. */
    423     public static final int PS_ENABLED = 1001;            // Access Control blocks data service
    424     public static final int PS_DISABLED = 1002;           // Access Control enables data service
    425     public static final int CS_ENABLED = 1003;            // Access Control blocks all voice/sms service
    426     public static final int CS_DISABLED = 1004;           // Access Control enables all voice/sms service
    427     public static final int CS_NORMAL_ENABLED = 1005;     // Access Control blocks normal voice/sms service
    428     public static final int CS_EMERGENCY_ENABLED = 1006;  // Access Control blocks emergency call service
    429     /** Notification id. */
    430     public static final int PS_NOTIFICATION = 888;  // Id to update and cancel PS restricted
    431     public static final int CS_NOTIFICATION = 999;  // Id to update and cancel CS restricted
    432     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    433         @Override
    434         public void onReceive(Context context, Intent intent) {
    435             if (!mPhone.isPhoneTypeGsm()) {
    436                 loge("Ignoring intent " + intent + " received on CDMA phone");
    437                 return;
    438             }
    439 
    440             if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
    441                 // update emergency string whenever locale changed
    442                 updateSpnDisplay();
    443             } else if (intent.getAction().equals(ACTION_RADIO_OFF)) {
    444                 mAlarmSwitch = false;
    445                 DcTracker dcTracker = mPhone.mDcTracker;
    446                 powerOffRadioSafely(dcTracker);
    447             }
    448         }
    449     };
    450 
    451     //CDMA
    452     // Min values used to by getOtasp()
    453     public static final String UNACTIVATED_MIN2_VALUE = "000000";
    454     public static final String UNACTIVATED_MIN_VALUE = "1111110111";
    455     // Current Otasp value
    456     private int mCurrentOtaspMode = OTASP_UNINITIALIZED;
    457     /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */
    458     public static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
    459     private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
    460             NITZ_UPDATE_SPACING_DEFAULT);
    461     /** If mNitzUpdateSpacing hasn't been exceeded but update is > mNitzUpdate do the update */
    462     public static final int NITZ_UPDATE_DIFF_DEFAULT = 2000;
    463     private int mNitzUpdateDiff = SystemProperties.getInt("ro.nitz_update_diff",
    464             NITZ_UPDATE_DIFF_DEFAULT);
    465     private int mRoamingIndicator;
    466     private boolean mIsInPrl;
    467     private int mDefaultRoamingIndicator;
    468     /**
    469      * Initially assume no data connection.
    470      */
    471     private int mRegistrationState = -1;
    472     private RegistrantList mCdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
    473     private String mMdn;
    474     private int mHomeSystemId[] = null;
    475     private int mHomeNetworkId[] = null;
    476     private String mMin;
    477     private String mPrlVersion;
    478     private boolean mIsMinInfoReady = false;
    479     private boolean mIsEriTextLoaded = false;
    480     private boolean mIsSubscriptionFromRuim = false;
    481     private CdmaSubscriptionSourceManager mCdmaSSM;
    482     public static final String INVALID_MCC = "000";
    483     public static final String DEFAULT_MNC = "00";
    484     private HbpcdUtils mHbpcdUtils = null;
    485     /* Used only for debugging purposes. */
    486     private String mRegistrationDeniedReason;
    487     private String mCurrentCarrier = null;
    488 
    489     public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
    490         mPhone = phone;
    491         mCi = ci;
    492 
    493         mRatRatcheter = new RatRatcheter(mPhone);
    494         mVoiceCapable = mPhone.getContext().getResources().getBoolean(
    495                 com.android.internal.R.bool.config_voice_capable);
    496         mUiccController = UiccController.getInstance();
    497 
    498         mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
    499         mCi.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
    500         mCi.registerForCellInfoList(this, EVENT_UNSOL_CELL_INFO_LIST, null);
    501 
    502         mSubscriptionController = SubscriptionController.getInstance();
    503         mSubscriptionManager = SubscriptionManager.from(phone.getContext());
    504         mSubscriptionManager
    505                 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
    506 
    507         mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
    508 
    509         PowerManager powerManager =
    510                 (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
    511         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
    512 
    513         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
    514         mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
    515         mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
    516 
    517         mCr = phone.getContext().getContentResolver();
    518         // system setting property AIRPLANE_MODE_ON is set in Settings.
    519         int airplaneMode = Settings.Global.getInt(mCr, Settings.Global.AIRPLANE_MODE_ON, 0);
    520         int enableCellularOnBoot = Settings.Global.getInt(mCr,
    521                 Settings.Global.ENABLE_CELLULAR_ON_BOOT, 1);
    522         mDesiredPowerState = (enableCellularOnBoot > 0) && ! (airplaneMode > 0);
    523 
    524         mCr.registerContentObserver(
    525                 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
    526                 mAutoTimeObserver);
    527         mCr.registerContentObserver(
    528                 Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
    529                 mAutoTimeZoneObserver);
    530         setSignalStrengthDefaultValues();
    531 
    532         // Monitor locale change
    533         Context context = mPhone.getContext();
    534         IntentFilter filter = new IntentFilter();
    535         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
    536         context.registerReceiver(mIntentReceiver, filter);
    537         filter = new IntentFilter();
    538         filter.addAction(ACTION_RADIO_OFF);
    539         context.registerReceiver(mIntentReceiver, filter);
    540 
    541         mEventLog = new TelephonyEventLog(mPhone.getPhoneId());
    542         mPhone.notifyOtaspChanged(OTASP_UNINITIALIZED);
    543 
    544         updatePhoneType();
    545     }
    546 
    547     @VisibleForTesting
    548     public void updatePhoneType() {
    549         mSS = new ServiceState();
    550         mNewSS = new ServiceState();
    551         mLastCellInfoListTime = 0;
    552         mLastCellInfoList = null;
    553         mSignalStrength = new SignalStrength();
    554         mRestrictedState = new RestrictedState();
    555         mStartedGprsRegCheck = false;
    556         mReportedGprsNoReg = false;
    557         mMdn = null;
    558         mMin = null;
    559         mPrlVersion = null;
    560         mIsMinInfoReady = false;
    561         mNitzUpdatedTime = false;
    562 
    563         //cancel any pending pollstate request on voice tech switching
    564         cancelPollState();
    565 
    566         if (mPhone.isPhoneTypeGsm()) {
    567             //clear CDMA registrations first
    568             if (mCdmaSSM != null) {
    569                 mCdmaSSM.dispose(this);
    570             }
    571 
    572             mCi.unregisterForCdmaPrlChanged(this);
    573             mPhone.unregisterForEriFileLoaded(this);
    574             mCi.unregisterForCdmaOtaProvision(this);
    575             mPhone.unregisterForSimRecordsLoaded(this);
    576 
    577             mCellLoc = new GsmCellLocation();
    578             mNewCellLoc = new GsmCellLocation();
    579             mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
    580             mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
    581         } else {
    582             //clear GSM regsitrations first
    583             mCi.unregisterForAvailable(this);
    584             mCi.unSetOnRestrictedStateChanged(this);
    585 
    586             if (mPhone.isPhoneTypeCdmaLte()) {
    587                 mPhone.registerForSimRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
    588             }
    589             mCellLoc = new CdmaCellLocation();
    590             mNewCellLoc = new CdmaCellLocation();
    591             mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(mPhone.getContext(), mCi, this,
    592                     EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
    593             mIsSubscriptionFromRuim = (mCdmaSSM.getCdmaSubscriptionSource() ==
    594                     CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM);
    595 
    596             mCi.registerForCdmaPrlChanged(this, EVENT_CDMA_PRL_VERSION_CHANGED, null);
    597             mPhone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null);
    598             mCi.registerForCdmaOtaProvision(this, EVENT_OTA_PROVISION_STATUS_CHANGE, null);
    599 
    600             mHbpcdUtils = new HbpcdUtils(mPhone.getContext());
    601             // update OTASP state in case previously set by another service
    602             updateOtaspState();
    603         }
    604 
    605         // This should be done after the technology specific initializations above since it relies
    606         // on fields like mIsSubscriptionFromRuim (which is updated above)
    607         onUpdateIccAvailability();
    608 
    609         mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
    610                 ServiceState.rilRadioTechnologyToString(ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN));
    611         // Query signal strength from the modem after service tracker is created (i.e. boot up,
    612         // switching between GSM and CDMA phone), because the unsolicited signal strength
    613         // information might come late or even never come. This will get the accurate signal
    614         // strength information displayed on the UI.
    615         mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
    616         sendMessage(obtainMessage(EVENT_PHONE_TYPE_SWITCHED));
    617     }
    618 
    619     @VisibleForTesting
    620     public void requestShutdown() {
    621         if (mDeviceShuttingDown == true) return;
    622         mDeviceShuttingDown = true;
    623         mDesiredPowerState = false;
    624         setPowerStateToDesired();
    625     }
    626 
    627     public void dispose() {
    628         mCi.unSetOnSignalStrengthUpdate(this);
    629         mUiccController.unregisterForIccChanged(this);
    630         mCi.unregisterForCellInfoList(this);
    631         mSubscriptionManager
    632             .removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
    633         mCi.unregisterForImsNetworkStateChanged(this);
    634     }
    635 
    636     public boolean getDesiredPowerState() {
    637         return mDesiredPowerState;
    638     }
    639     public boolean getPowerStateFromCarrier() { return !mRadioDisabledByCarrier; }
    640 
    641     private SignalStrength mLastSignalStrength = null;
    642     protected boolean notifySignalStrength() {
    643         boolean notified = false;
    644         if (!mSignalStrength.equals(mLastSignalStrength)) {
    645             try {
    646                 mPhone.notifySignalStrength();
    647                 notified = true;
    648             } catch (NullPointerException ex) {
    649                 loge("updateSignalStrength() Phone already destroyed: " + ex
    650                         + "SignalStrength not notified");
    651             }
    652         }
    653         return notified;
    654     }
    655 
    656     /**
    657      * Notify all mDataConnectionRatChangeRegistrants using an
    658      * AsyncResult in msg.obj where AsyncResult#result contains the
    659      * new RAT as an Integer Object.
    660      */
    661     protected void notifyDataRegStateRilRadioTechnologyChanged() {
    662         int rat = mSS.getRilDataRadioTechnology();
    663         int drs = mSS.getDataRegState();
    664         if (DBG) log("notifyDataRegStateRilRadioTechnologyChanged: drs=" + drs + " rat=" + rat);
    665 
    666         mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
    667                 ServiceState.rilRadioTechnologyToString(rat));
    668         mDataRegStateOrRatChangedRegistrants.notifyResult(new Pair<Integer, Integer>(drs, rat));
    669     }
    670 
    671     /**
    672      * Some operators have been known to report registration failure
    673      * data only devices, to fix that use DataRegState.
    674      */
    675     protected void useDataRegStateForDataOnlyDevices() {
    676         if (mVoiceCapable == false) {
    677             if (DBG) {
    678                 log("useDataRegStateForDataOnlyDevice: VoiceRegState=" + mNewSS.getVoiceRegState()
    679                     + " DataRegState=" + mNewSS.getDataRegState());
    680             }
    681             // TODO: Consider not lying and instead have callers know the difference.
    682             mNewSS.setVoiceRegState(mNewSS.getDataRegState());
    683         }
    684     }
    685 
    686     protected void updatePhoneObject() {
    687         if (mPhone.getContext().getResources().
    688                 getBoolean(com.android.internal.R.bool.config_switch_phone_on_voice_reg_state_change)) {
    689             // If the phone is not registered on a network, no need to update.
    690             boolean isRegistered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE ||
    691                     mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY;
    692             if (!isRegistered) {
    693                 log("updatePhoneObject: Ignore update");
    694                 return;
    695             }
    696             mPhone.updatePhoneObject(mSS.getRilVoiceRadioTechnology());
    697         }
    698     }
    699 
    700     /**
    701      * Registration point for combined roaming on of mobile voice
    702      * combined roaming is true when roaming is true and ONS differs SPN
    703      *
    704      * @param h handler to notify
    705      * @param what what code of message when delivered
    706      * @param obj placed in Message.obj
    707      */
    708     public void registerForVoiceRoamingOn(Handler h, int what, Object obj) {
    709         Registrant r = new Registrant(h, what, obj);
    710         mVoiceRoamingOnRegistrants.add(r);
    711 
    712         if (mSS.getVoiceRoaming()) {
    713             r.notifyRegistrant();
    714         }
    715     }
    716 
    717     public void unregisterForVoiceRoamingOn(Handler h) {
    718         mVoiceRoamingOnRegistrants.remove(h);
    719     }
    720 
    721     /**
    722      * Registration point for roaming off of mobile voice
    723      * combined roaming is true when roaming is true and ONS differs SPN
    724      *
    725      * @param h handler to notify
    726      * @param what what code of message when delivered
    727      * @param obj placed in Message.obj
    728      */
    729     public void registerForVoiceRoamingOff(Handler h, int what, Object obj) {
    730         Registrant r = new Registrant(h, what, obj);
    731         mVoiceRoamingOffRegistrants.add(r);
    732 
    733         if (!mSS.getVoiceRoaming()) {
    734             r.notifyRegistrant();
    735         }
    736     }
    737 
    738     public void unregisterForVoiceRoamingOff(Handler h) {
    739         mVoiceRoamingOffRegistrants.remove(h);
    740     }
    741 
    742     /**
    743      * Registration point for combined roaming on of mobile data
    744      * combined roaming is true when roaming is true and ONS differs SPN
    745      *
    746      * @param h handler to notify
    747      * @param what what code of message when delivered
    748      * @param obj placed in Message.obj
    749      */
    750     public void registerForDataRoamingOn(Handler h, int what, Object obj) {
    751         Registrant r = new Registrant(h, what, obj);
    752         mDataRoamingOnRegistrants.add(r);
    753 
    754         if (mSS.getDataRoaming()) {
    755             r.notifyRegistrant();
    756         }
    757     }
    758 
    759     public void unregisterForDataRoamingOn(Handler h) {
    760         mDataRoamingOnRegistrants.remove(h);
    761     }
    762 
    763     /**
    764      * Registration point for roaming off of mobile data
    765      * combined roaming is true when roaming is true and ONS differs SPN
    766      *
    767      * @param h handler to notify
    768      * @param what what code of message when delivered
    769      * @param obj placed in Message.obj
    770      */
    771     public void registerForDataRoamingOff(Handler h, int what, Object obj) {
    772         Registrant r = new Registrant(h, what, obj);
    773         mDataRoamingOffRegistrants.add(r);
    774 
    775         if (!mSS.getDataRoaming()) {
    776             r.notifyRegistrant();
    777         }
    778     }
    779 
    780     public void unregisterForDataRoamingOff(Handler h) {
    781         mDataRoamingOffRegistrants.remove(h);
    782     }
    783 
    784     /**
    785      * Re-register network by toggling preferred network type.
    786      * This is a work-around to deregister and register network since there is
    787      * no ril api to set COPS=2 (deregister) only.
    788      *
    789      * @param onComplete is dispatched when this is complete.  it will be
    790      * an AsyncResult, and onComplete.obj.exception will be non-null
    791      * on failure.
    792      */
    793     public void reRegisterNetwork(Message onComplete) {
    794         mCi.getPreferredNetworkType(
    795                 obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete));
    796     }
    797 
    798     public void
    799     setRadioPower(boolean power) {
    800         mDesiredPowerState = power;
    801 
    802         setPowerStateToDesired();
    803     }
    804 
    805     /**
    806      * Radio power set from carrier action. if set to false means carrier desire to turn radio off
    807      * and radio wont be re-enabled unless carrier explicitly turn it back on.
    808      * @param enable indicate if radio power is enabled or disabled from carrier action.
    809      */
    810     public void setRadioPowerFromCarrier(boolean enable) {
    811         mRadioDisabledByCarrier = !enable;
    812         setPowerStateToDesired();
    813     }
    814 
    815     /**
    816      * These two flags manage the behavior of the cell lock -- the
    817      * lock should be held if either flag is true.  The intention is
    818      * to allow temporary acquisition of the lock to get a single
    819      * update.  Such a lock grab and release can thus be made to not
    820      * interfere with more permanent lock holds -- in other words, the
    821      * lock will only be released if both flags are false, and so
    822      * releases by temporary users will only affect the lock state if
    823      * there is no continuous user.
    824      */
    825     private boolean mWantContinuousLocationUpdates;
    826     private boolean mWantSingleLocationUpdate;
    827 
    828     public void enableSingleLocationUpdate() {
    829         if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return;
    830         mWantSingleLocationUpdate = true;
    831         mCi.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
    832     }
    833 
    834     public void enableLocationUpdates() {
    835         if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return;
    836         mWantContinuousLocationUpdates = true;
    837         mCi.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
    838     }
    839 
    840     protected void disableSingleLocationUpdate() {
    841         mWantSingleLocationUpdate = false;
    842         if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) {
    843             mCi.setLocationUpdates(false, null);
    844         }
    845     }
    846 
    847     public void disableLocationUpdates() {
    848         mWantContinuousLocationUpdates = false;
    849         if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) {
    850             mCi.setLocationUpdates(false, null);
    851         }
    852     }
    853 
    854     @Override
    855     public void handleMessage(Message msg) {
    856         AsyncResult ar;
    857         int[] ints;
    858         Message message;
    859         switch (msg.what) {
    860             case EVENT_SET_RADIO_POWER_OFF:
    861                 synchronized(this) {
    862                     if (mPendingRadioPowerOffAfterDataOff &&
    863                             (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) {
    864                         if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
    865                         hangupAndPowerOff();
    866                         mPendingRadioPowerOffAfterDataOffTag += 1;
    867                         mPendingRadioPowerOffAfterDataOff = false;
    868                     } else {
    869                         log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 +
    870                                 "!= tag=" + mPendingRadioPowerOffAfterDataOffTag);
    871                     }
    872                 }
    873                 break;
    874 
    875             case EVENT_ICC_CHANGED:
    876                 onUpdateIccAvailability();
    877                 break;
    878 
    879             case EVENT_GET_CELL_INFO_LIST: {
    880                 ar = (AsyncResult) msg.obj;
    881                 CellInfoResult result = (CellInfoResult) ar.userObj;
    882                 synchronized(result.lockObj) {
    883                     if (ar.exception != null) {
    884                         log("EVENT_GET_CELL_INFO_LIST: error ret null, e=" + ar.exception);
    885                         result.list = null;
    886                     } else {
    887                         result.list = (List<CellInfo>) ar.result;
    888 
    889                         if (VDBG) {
    890                             log("EVENT_GET_CELL_INFO_LIST: size=" + result.list.size()
    891                                     + " list=" + result.list);
    892                         }
    893                     }
    894                     mLastCellInfoListTime = SystemClock.elapsedRealtime();
    895                     mLastCellInfoList = result.list;
    896                     result.lockObj.notify();
    897                 }
    898                 break;
    899             }
    900 
    901             case EVENT_UNSOL_CELL_INFO_LIST: {
    902                 ar = (AsyncResult) msg.obj;
    903                 if (ar.exception != null) {
    904                     log("EVENT_UNSOL_CELL_INFO_LIST: error ignoring, e=" + ar.exception);
    905                 } else {
    906                     List<CellInfo> list = (List<CellInfo>) ar.result;
    907                     if (VDBG) {
    908                         log("EVENT_UNSOL_CELL_INFO_LIST: size=" + list.size() + " list=" + list);
    909                     }
    910                     mLastCellInfoListTime = SystemClock.elapsedRealtime();
    911                     mLastCellInfoList = list;
    912                     mPhone.notifyCellInfo(list);
    913                 }
    914                 break;
    915             }
    916 
    917             case  EVENT_IMS_STATE_CHANGED: // received unsol
    918                 mCi.getImsRegistrationState(this.obtainMessage(EVENT_IMS_STATE_DONE));
    919                 break;
    920 
    921             case EVENT_IMS_STATE_DONE:
    922                 ar = (AsyncResult) msg.obj;
    923                 if (ar.exception == null) {
    924                     int[] responseArray = (int[])ar.result;
    925                     mImsRegistered = (responseArray[0] == 1) ? true : false;
    926                 }
    927                 break;
    928 
    929             //GSM
    930             case EVENT_RADIO_AVAILABLE:
    931                 //this is unnecessary
    932                 //setPowerStateToDesired();
    933                 break;
    934 
    935             case EVENT_SIM_READY:
    936                 // Reset the mPreviousSubId so we treat a SIM power bounce
    937                 // as a first boot.  See b/19194287
    938                 mOnSubscriptionsChangedListener.mPreviousSubId.set(-1);
    939                 pollState();
    940                 // Signal strength polling stops when radio is off
    941                 queueNextSignalStrengthPoll();
    942                 break;
    943 
    944             case EVENT_RADIO_STATE_CHANGED:
    945             case EVENT_PHONE_TYPE_SWITCHED:
    946                 if(!mPhone.isPhoneTypeGsm() &&
    947                         mCi.getRadioState() == CommandsInterface.RadioState.RADIO_ON) {
    948                     handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource());
    949 
    950                     // Signal strength polling stops when radio is off.
    951                     queueNextSignalStrengthPoll();
    952                 }
    953                 // This will do nothing in the 'radio not available' case
    954                 setPowerStateToDesired();
    955                 // These events are modem triggered, so pollState() needs to be forced
    956                 modemTriggeredPollState();
    957                 break;
    958 
    959             case EVENT_NETWORK_STATE_CHANGED:
    960                 modemTriggeredPollState();
    961                 break;
    962 
    963             case EVENT_GET_SIGNAL_STRENGTH:
    964                 // This callback is called when signal strength is polled
    965                 // all by itself
    966 
    967                 if (!(mCi.getRadioState().isOn())) {
    968                     // Polling will continue when radio turns back on
    969                     return;
    970                 }
    971                 ar = (AsyncResult) msg.obj;
    972                 onSignalStrengthResult(ar);
    973                 queueNextSignalStrengthPoll();
    974 
    975                 break;
    976 
    977             case EVENT_GET_LOC_DONE:
    978                 ar = (AsyncResult) msg.obj;
    979 
    980                 if (ar.exception == null) {
    981                     String states[] = (String[])ar.result;
    982                     if (mPhone.isPhoneTypeGsm()) {
    983                         int lac = -1;
    984                         int cid = -1;
    985                         if (states.length >= 3) {
    986                             try {
    987                                 if (states[1] != null && states[1].length() > 0) {
    988                                     lac = Integer.parseInt(states[1], 16);
    989                                 }
    990                                 if (states[2] != null && states[2].length() > 0) {
    991                                     cid = Integer.parseInt(states[2], 16);
    992                                 }
    993                             } catch (NumberFormatException ex) {
    994                                 Rlog.w(LOG_TAG, "error parsing location: " + ex);
    995                             }
    996                         }
    997                         ((GsmCellLocation)mCellLoc).setLacAndCid(lac, cid);
    998                     } else {
    999                         int baseStationId = -1;
   1000                         int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG;
   1001                         int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
   1002                         int systemId = -1;
   1003                         int networkId = -1;
   1004 
   1005                         if (states.length > 9) {
   1006                             try {
   1007                                 if (states[4] != null) {
   1008                                     baseStationId = Integer.parseInt(states[4]);
   1009                                 }
   1010                                 if (states[5] != null) {
   1011                                     baseStationLatitude = Integer.parseInt(states[5]);
   1012                                 }
   1013                                 if (states[6] != null) {
   1014                                     baseStationLongitude = Integer.parseInt(states[6]);
   1015                                 }
   1016                                 // Some carriers only return lat-lngs of 0,0
   1017                                 if (baseStationLatitude == 0 && baseStationLongitude == 0) {
   1018                                     baseStationLatitude  = CdmaCellLocation.INVALID_LAT_LONG;
   1019                                     baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
   1020                                 }
   1021                                 if (states[8] != null) {
   1022                                     systemId = Integer.parseInt(states[8]);
   1023                                 }
   1024                                 if (states[9] != null) {
   1025                                     networkId = Integer.parseInt(states[9]);
   1026                                 }
   1027                             } catch (NumberFormatException ex) {
   1028                                 loge("error parsing cell location data: " + ex);
   1029                             }
   1030                         }
   1031 
   1032                         ((CdmaCellLocation)mCellLoc).setCellLocationData(baseStationId,
   1033                                 baseStationLatitude, baseStationLongitude, systemId, networkId);
   1034                     }
   1035                     mPhone.notifyLocationChanged();
   1036                 }
   1037 
   1038                 // Release any temporary cell lock, which could have been
   1039                 // acquired to allow a single-shot location update.
   1040                 disableSingleLocationUpdate();
   1041                 break;
   1042 
   1043             case EVENT_POLL_STATE_REGISTRATION:
   1044             case EVENT_POLL_STATE_GPRS:
   1045             case EVENT_POLL_STATE_OPERATOR:
   1046                 ar = (AsyncResult) msg.obj;
   1047                 handlePollStateResult(msg.what, ar);
   1048                 break;
   1049 
   1050             case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
   1051                 if (DBG) log("EVENT_POLL_STATE_NETWORK_SELECTION_MODE");
   1052                 ar = (AsyncResult) msg.obj;
   1053                 if (mPhone.isPhoneTypeGsm()) {
   1054                     handlePollStateResult(msg.what, ar);
   1055                 } else {
   1056                     if (ar.exception == null && ar.result != null) {
   1057                         ints = (int[])ar.result;
   1058                         if (ints[0] == 1) {  // Manual selection.
   1059                             mPhone.setNetworkSelectionModeAutomatic(null);
   1060                         }
   1061                     } else {
   1062                         log("Unable to getNetworkSelectionMode");
   1063                     }
   1064                 }
   1065                 break;
   1066 
   1067             case EVENT_POLL_SIGNAL_STRENGTH:
   1068                 // Just poll signal strength...not part of pollState()
   1069 
   1070                 mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
   1071                 break;
   1072 
   1073             case EVENT_NITZ_TIME:
   1074                 ar = (AsyncResult) msg.obj;
   1075 
   1076                 String nitzString = (String)((Object[])ar.result)[0];
   1077                 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
   1078 
   1079                 setTimeFromNITZString(nitzString, nitzReceiveTime);
   1080                 break;
   1081 
   1082             case EVENT_SIGNAL_STRENGTH_UPDATE:
   1083                 // This is a notification from CommandsInterface.setOnSignalStrengthUpdate
   1084 
   1085                 ar = (AsyncResult) msg.obj;
   1086 
   1087                 // The radio is telling us about signal strength changes
   1088                 // we don't have to ask it
   1089                 mDontPollSignalStrength = true;
   1090 
   1091                 onSignalStrengthResult(ar);
   1092                 break;
   1093 
   1094             case EVENT_SIM_RECORDS_LOADED:
   1095                 log("EVENT_SIM_RECORDS_LOADED: what=" + msg.what);
   1096                 updatePhoneObject();
   1097                 updateOtaspState();
   1098                 if (mPhone.isPhoneTypeGsm()) {
   1099                     updateSpnDisplay();
   1100                 }
   1101                 break;
   1102 
   1103             case EVENT_LOCATION_UPDATES_ENABLED:
   1104                 ar = (AsyncResult) msg.obj;
   1105 
   1106                 if (ar.exception == null) {
   1107                     mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null));
   1108                 }
   1109                 break;
   1110 
   1111             case EVENT_SET_PREFERRED_NETWORK_TYPE:
   1112                 ar = (AsyncResult) msg.obj;
   1113                 // Don't care the result, only use for dereg network (COPS=2)
   1114                 message = obtainMessage(EVENT_RESET_PREFERRED_NETWORK_TYPE, ar.userObj);
   1115                 mCi.setPreferredNetworkType(mPreferredNetworkType, message);
   1116                 break;
   1117 
   1118             case EVENT_RESET_PREFERRED_NETWORK_TYPE:
   1119                 ar = (AsyncResult) msg.obj;
   1120                 if (ar.userObj != null) {
   1121                     AsyncResult.forMessage(((Message) ar.userObj)).exception
   1122                             = ar.exception;
   1123                     ((Message) ar.userObj).sendToTarget();
   1124                 }
   1125                 break;
   1126 
   1127             case EVENT_GET_PREFERRED_NETWORK_TYPE:
   1128                 ar = (AsyncResult) msg.obj;
   1129 
   1130                 if (ar.exception == null) {
   1131                     mPreferredNetworkType = ((int[])ar.result)[0];
   1132                 } else {
   1133                     mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
   1134                 }
   1135 
   1136                 message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj);
   1137                 int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
   1138 
   1139                 mCi.setPreferredNetworkType(toggledNetworkType, message);
   1140                 break;
   1141 
   1142             case EVENT_CHECK_REPORT_GPRS:
   1143                 if (mPhone.isPhoneTypeGsm() && mSS != null &&
   1144                         !isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
   1145 
   1146                     // Can't register data service while voice service is ok
   1147                     // i.e. CREG is ok while CGREG is not
   1148                     // possible a network or baseband side error
   1149                     GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
   1150                     EventLog.writeEvent(EventLogTags.DATA_NETWORK_REGISTRATION_FAIL,
   1151                             mSS.getOperatorNumeric(), loc != null ? loc.getCid() : -1);
   1152                     mReportedGprsNoReg = true;
   1153                 }
   1154                 mStartedGprsRegCheck = false;
   1155                 break;
   1156 
   1157             case EVENT_RESTRICTED_STATE_CHANGED:
   1158                 if (mPhone.isPhoneTypeGsm()) {
   1159                     // This is a notification from
   1160                     // CommandsInterface.setOnRestrictedStateChanged
   1161 
   1162                     if (DBG) log("EVENT_RESTRICTED_STATE_CHANGED");
   1163 
   1164                     ar = (AsyncResult) msg.obj;
   1165 
   1166                     onRestrictedStateChanged(ar);
   1167                 }
   1168                 break;
   1169 
   1170             case EVENT_ALL_DATA_DISCONNECTED:
   1171                 int dds = SubscriptionManager.getDefaultDataSubscriptionId();
   1172                 ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this);
   1173                 synchronized(this) {
   1174                     if (mPendingRadioPowerOffAfterDataOff) {
   1175                         if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now.");
   1176                         hangupAndPowerOff();
   1177                         mPendingRadioPowerOffAfterDataOff = false;
   1178                     } else {
   1179                         log("EVENT_ALL_DATA_DISCONNECTED is stale");
   1180                     }
   1181                 }
   1182                 break;
   1183 
   1184             case EVENT_CHANGE_IMS_STATE:
   1185                 if (DBG) log("EVENT_CHANGE_IMS_STATE:");
   1186 
   1187                 setPowerStateToDesired();
   1188                 break;
   1189 
   1190             case EVENT_IMS_CAPABILITY_CHANGED:
   1191                 if (DBG) log("EVENT_IMS_CAPABILITY_CHANGED");
   1192                 updateSpnDisplay();
   1193                 break;
   1194 
   1195             //CDMA
   1196             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
   1197                 handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource());
   1198                 break;
   1199 
   1200             case EVENT_RUIM_READY:
   1201                 if (mPhone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
   1202                     // Subscription will be read from SIM I/O
   1203                     if (DBG) log("Receive EVENT_RUIM_READY");
   1204                     pollState();
   1205                 } else {
   1206                     if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
   1207                     getSubscriptionInfoAndStartPollingThreads();
   1208                 }
   1209 
   1210                 // Only support automatic selection mode in CDMA.
   1211                 mCi.getNetworkSelectionMode(obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE));
   1212 
   1213                 break;
   1214 
   1215             case EVENT_NV_READY:
   1216                 updatePhoneObject();
   1217 
   1218                 // Only support automatic selection mode in CDMA.
   1219                 mCi.getNetworkSelectionMode(obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE));
   1220 
   1221                 // For Non-RUIM phones, the subscription information is stored in
   1222                 // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA
   1223                 // subscription info.
   1224                 getSubscriptionInfoAndStartPollingThreads();
   1225                 break;
   1226 
   1227             case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION
   1228                 if (!mPhone.isPhoneTypeGsm()) {
   1229                     ar = (AsyncResult) msg.obj;
   1230 
   1231                     if (ar.exception == null) {
   1232                         String cdmaSubscription[] = (String[]) ar.result;
   1233                         if (cdmaSubscription != null && cdmaSubscription.length >= 5) {
   1234                             mMdn = cdmaSubscription[0];
   1235                             parseSidNid(cdmaSubscription[1], cdmaSubscription[2]);
   1236 
   1237                             mMin = cdmaSubscription[3];
   1238                             mPrlVersion = cdmaSubscription[4];
   1239                             if (DBG) log("GET_CDMA_SUBSCRIPTION: MDN=" + mMdn);
   1240 
   1241                             mIsMinInfoReady = true;
   1242 
   1243                             updateOtaspState();
   1244                             // Notify apps subscription info is ready
   1245                             notifyCdmaSubscriptionInfoReady();
   1246 
   1247                             if (!mIsSubscriptionFromRuim && mIccRecords != null) {
   1248                                 if (DBG) {
   1249                                     log("GET_CDMA_SUBSCRIPTION set imsi in mIccRecords");
   1250                                 }
   1251                                 mIccRecords.setImsi(getImsi());
   1252                             } else {
   1253                                 if (DBG) {
   1254                                     log("GET_CDMA_SUBSCRIPTION either mIccRecords is null or NV " +
   1255                                             "type device - not setting Imsi in mIccRecords");
   1256                                 }
   1257                             }
   1258                         } else {
   1259                             if (DBG) {
   1260                                 log("GET_CDMA_SUBSCRIPTION: error parsing cdmaSubscription " +
   1261                                         "params num=" + cdmaSubscription.length);
   1262                             }
   1263                         }
   1264                     }
   1265                 }
   1266                 break;
   1267 
   1268             case EVENT_RUIM_RECORDS_LOADED:
   1269                 if (!mPhone.isPhoneTypeGsm()) {
   1270                     log("EVENT_RUIM_RECORDS_LOADED: what=" + msg.what);
   1271                     updatePhoneObject();
   1272                     if (mPhone.isPhoneTypeCdma()) {
   1273                         updateSpnDisplay();
   1274                     } else {
   1275                         RuimRecords ruim = (RuimRecords) mIccRecords;
   1276                         if (ruim != null) {
   1277                             if (ruim.isProvisioned()) {
   1278                                 mMdn = ruim.getMdn();
   1279                                 mMin = ruim.getMin();
   1280                                 parseSidNid(ruim.getSid(), ruim.getNid());
   1281                                 mPrlVersion = ruim.getPrlVersion();
   1282                                 mIsMinInfoReady = true;
   1283                             }
   1284                             updateOtaspState();
   1285                             // Notify apps subscription info is ready
   1286                             notifyCdmaSubscriptionInfoReady();
   1287                         }
   1288                         // SID/NID/PRL is loaded. Poll service state
   1289                         // again to update to the roaming state with
   1290                         // the latest variables.
   1291                         pollState();
   1292                     }
   1293                 }
   1294                 break;
   1295 
   1296             case EVENT_ERI_FILE_LOADED:
   1297                 // Repoll the state once the ERI file has been loaded.
   1298                 if (DBG) log("ERI file has been loaded, repolling.");
   1299                 pollState();
   1300                 break;
   1301 
   1302             case EVENT_OTA_PROVISION_STATUS_CHANGE:
   1303                 ar = (AsyncResult)msg.obj;
   1304                 if (ar.exception == null) {
   1305                     ints = (int[]) ar.result;
   1306                     int otaStatus = ints[0];
   1307                     if (otaStatus == Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED
   1308                             || otaStatus == Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) {
   1309                         if (DBG) log("EVENT_OTA_PROVISION_STATUS_CHANGE: Complete, Reload MDN");
   1310                         mCi.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
   1311                     }
   1312                 }
   1313                 break;
   1314 
   1315             case EVENT_CDMA_PRL_VERSION_CHANGED:
   1316                 ar = (AsyncResult)msg.obj;
   1317                 if (ar.exception == null) {
   1318                     ints = (int[]) ar.result;
   1319                     mPrlVersion = Integer.toString(ints[0]);
   1320                 }
   1321                 break;
   1322 
   1323             default:
   1324                 log("Unhandled message with number: " + msg.what);
   1325                 break;
   1326         }
   1327     }
   1328 
   1329     protected boolean isSidsAllZeros() {
   1330         if (mHomeSystemId != null) {
   1331             for (int i=0; i < mHomeSystemId.length; i++) {
   1332                 if (mHomeSystemId[i] != 0) {
   1333                     return false;
   1334                 }
   1335             }
   1336         }
   1337         return true;
   1338     }
   1339 
   1340     /**
   1341      * Check whether a specified system ID that matches one of the home system IDs.
   1342      */
   1343     private boolean isHomeSid(int sid) {
   1344         if (mHomeSystemId != null) {
   1345             for (int i=0; i < mHomeSystemId.length; i++) {
   1346                 if (sid == mHomeSystemId[i]) {
   1347                     return true;
   1348                 }
   1349             }
   1350         }
   1351         return false;
   1352     }
   1353 
   1354     public String getMdnNumber() {
   1355         return mMdn;
   1356     }
   1357 
   1358     public String getCdmaMin() {
   1359         return mMin;
   1360     }
   1361 
   1362     /** Returns null if NV is not yet ready */
   1363     public String getPrlVersion() {
   1364         return mPrlVersion;
   1365     }
   1366 
   1367     /**
   1368      * Returns IMSI as MCC + MNC + MIN
   1369      */
   1370     public String getImsi() {
   1371         // TODO: When RUIM is enabled, IMSI will come from RUIM not build-time props.
   1372         String operatorNumeric = ((TelephonyManager) mPhone.getContext().
   1373                 getSystemService(Context.TELEPHONY_SERVICE)).
   1374                 getSimOperatorNumericForPhone(mPhone.getPhoneId());
   1375 
   1376         if (!TextUtils.isEmpty(operatorNumeric) && getCdmaMin() != null) {
   1377             return (operatorNumeric + getCdmaMin());
   1378         } else {
   1379             return null;
   1380         }
   1381     }
   1382 
   1383     /**
   1384      * Check if subscription data has been assigned to mMin
   1385      *
   1386      * return true if MIN info is ready; false otherwise.
   1387      */
   1388     public boolean isMinInfoReady() {
   1389         return mIsMinInfoReady;
   1390     }
   1391 
   1392     /**
   1393      * Returns OTASP_UNKNOWN, OTASP_UNINITIALIZED, OTASP_NEEDED or OTASP_NOT_NEEDED
   1394      */
   1395     public int getOtasp() {
   1396         int provisioningState;
   1397         // if sim is not loaded, return otasp uninitialized
   1398         if(!mPhone.getIccRecordsLoaded()) {
   1399             if(DBG) log("getOtasp: otasp uninitialized due to sim not loaded");
   1400             return OTASP_UNINITIALIZED;
   1401         }
   1402         // if voice tech is Gsm, return otasp not needed
   1403         if(mPhone.isPhoneTypeGsm()) {
   1404             if(DBG) log("getOtasp: otasp not needed for GSM");
   1405             return OTASP_NOT_NEEDED;
   1406         }
   1407         // for ruim, min is null means require otasp.
   1408         if (mIsSubscriptionFromRuim && mMin == null) {
   1409             return OTASP_NEEDED;
   1410         }
   1411         if (mMin == null || (mMin.length() < 6)) {
   1412             if (DBG) log("getOtasp: bad mMin='" + mMin + "'");
   1413             provisioningState = OTASP_UNKNOWN;
   1414         } else {
   1415             if ((mMin.equals(UNACTIVATED_MIN_VALUE)
   1416                     || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
   1417                     || SystemProperties.getBoolean("test_cdma_setup", false)) {
   1418                 provisioningState = OTASP_NEEDED;
   1419             } else {
   1420                 provisioningState = OTASP_NOT_NEEDED;
   1421             }
   1422         }
   1423         if (DBG) log("getOtasp: state=" + provisioningState);
   1424         return provisioningState;
   1425     }
   1426 
   1427     protected void parseSidNid (String sidStr, String nidStr) {
   1428         if (sidStr != null) {
   1429             String[] sid = sidStr.split(",");
   1430             mHomeSystemId = new int[sid.length];
   1431             for (int i = 0; i < sid.length; i++) {
   1432                 try {
   1433                     mHomeSystemId[i] = Integer.parseInt(sid[i]);
   1434                 } catch (NumberFormatException ex) {
   1435                     loge("error parsing system id: " + ex);
   1436                 }
   1437             }
   1438         }
   1439         if (DBG) log("CDMA_SUBSCRIPTION: SID=" + sidStr);
   1440 
   1441         if (nidStr != null) {
   1442             String[] nid = nidStr.split(",");
   1443             mHomeNetworkId = new int[nid.length];
   1444             for (int i = 0; i < nid.length; i++) {
   1445                 try {
   1446                     mHomeNetworkId[i] = Integer.parseInt(nid[i]);
   1447                 } catch (NumberFormatException ex) {
   1448                     loge("CDMA_SUBSCRIPTION: error parsing network id: " + ex);
   1449                 }
   1450             }
   1451         }
   1452         if (DBG) log("CDMA_SUBSCRIPTION: NID=" + nidStr);
   1453     }
   1454 
   1455     protected void updateOtaspState() {
   1456         int otaspMode = getOtasp();
   1457         int oldOtaspMode = mCurrentOtaspMode;
   1458         mCurrentOtaspMode = otaspMode;
   1459 
   1460         if (oldOtaspMode != mCurrentOtaspMode) {
   1461             if (DBG) {
   1462                 log("updateOtaspState: call notifyOtaspChanged old otaspMode=" +
   1463                         oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode);
   1464             }
   1465             mPhone.notifyOtaspChanged(mCurrentOtaspMode);
   1466         }
   1467     }
   1468 
   1469     protected Phone getPhone() {
   1470         return mPhone;
   1471     }
   1472 
   1473     protected void handlePollStateResult(int what, AsyncResult ar) {
   1474         // Ignore stale requests from last poll
   1475         if (ar.userObj != mPollingContext) return;
   1476 
   1477         if (ar.exception != null) {
   1478             CommandException.Error err=null;
   1479 
   1480             if (ar.exception instanceof CommandException) {
   1481                 err = ((CommandException)(ar.exception)).getCommandError();
   1482             }
   1483 
   1484             if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
   1485                 // Radio has crashed or turned off
   1486                 cancelPollState();
   1487                 return;
   1488             }
   1489 
   1490             if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
   1491                 loge("RIL implementation has returned an error where it must succeed" +
   1492                         ar.exception);
   1493             }
   1494         } else try {
   1495             handlePollStateResultMessage(what, ar);
   1496         } catch (RuntimeException ex) {
   1497             loge("Exception while polling service state. Probably malformed RIL response." + ex);
   1498         }
   1499 
   1500         mPollingContext[0]--;
   1501 
   1502         if (mPollingContext[0] == 0) {
   1503             if (mPhone.isPhoneTypeGsm()) {
   1504                 updateRoamingState();
   1505                 mNewSS.setEmergencyOnly(mEmergencyOnly);
   1506             } else {
   1507                 boolean namMatch = false;
   1508                 if (!isSidsAllZeros() && isHomeSid(mNewSS.getSystemId())) {
   1509                     namMatch = true;
   1510                 }
   1511 
   1512                 // Setting SS Roaming (general)
   1513                 if (mIsSubscriptionFromRuim) {
   1514                     mNewSS.setVoiceRoaming(isRoamingBetweenOperators(mNewSS.getVoiceRoaming(), mNewSS));
   1515                 }
   1516                 // For CDMA, voice and data should have the same roaming status
   1517                 final boolean isVoiceInService =
   1518                         (mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
   1519                 final int dataRegType = mNewSS.getRilDataRadioTechnology();
   1520                 if (isVoiceInService && ServiceState.isCdma(dataRegType)) {
   1521                     mNewSS.setDataRoaming(mNewSS.getVoiceRoaming());
   1522                 }
   1523 
   1524                 // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
   1525                 mNewSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
   1526                 mNewSS.setCdmaRoamingIndicator(mRoamingIndicator);
   1527                 boolean isPrlLoaded = true;
   1528                 if (TextUtils.isEmpty(mPrlVersion)) {
   1529                     isPrlLoaded = false;
   1530                 }
   1531                 if (!isPrlLoaded || (mNewSS.getRilVoiceRadioTechnology()
   1532                         == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
   1533                     log("Turn off roaming indicator if !isPrlLoaded or voice RAT is unknown");
   1534                     mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
   1535                 } else if (!isSidsAllZeros()) {
   1536                     if (!namMatch && !mIsInPrl) {
   1537                         // Use default
   1538                         mNewSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator);
   1539                     } else if (namMatch && !mIsInPrl) {
   1540                         // TODO this will be removed when we handle roaming on LTE on CDMA+LTE phones
   1541                         if (ServiceState.isLte(mNewSS.getRilVoiceRadioTechnology())) {
   1542                             log("Turn off roaming indicator as voice is LTE");
   1543                             mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
   1544                         } else {
   1545                             mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
   1546                         }
   1547                     } else if (!namMatch && mIsInPrl) {
   1548                         // Use the one from PRL/ERI
   1549                         mNewSS.setCdmaRoamingIndicator(mRoamingIndicator);
   1550                     } else {
   1551                         // It means namMatch && mIsInPrl
   1552                         if ((mRoamingIndicator <= 2)) {
   1553                             mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
   1554                         } else {
   1555                             // Use the one from PRL/ERI
   1556                             mNewSS.setCdmaRoamingIndicator(mRoamingIndicator);
   1557                         }
   1558                     }
   1559                 }
   1560 
   1561                 int roamingIndicator = mNewSS.getCdmaRoamingIndicator();
   1562                 mNewSS.setCdmaEriIconIndex(mPhone.mEriManager.getCdmaEriIconIndex(roamingIndicator,
   1563                         mDefaultRoamingIndicator));
   1564                 mNewSS.setCdmaEriIconMode(mPhone.mEriManager.getCdmaEriIconMode(roamingIndicator,
   1565                         mDefaultRoamingIndicator));
   1566 
   1567                 // NOTE: Some operator may require overriding mCdmaRoaming
   1568                 // (set by the modem), depending on the mRoamingIndicator.
   1569 
   1570                 if (DBG) {
   1571                     log("Set CDMA Roaming Indicator to: " + mNewSS.getCdmaRoamingIndicator()
   1572                             + ". voiceRoaming = " + mNewSS.getVoiceRoaming()
   1573                             + ". dataRoaming = " + mNewSS.getDataRoaming()
   1574                             + ", isPrlLoaded = " + isPrlLoaded
   1575                             + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl
   1576                             + ", mRoamingIndicator = " + mRoamingIndicator
   1577                             + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator);
   1578                 }
   1579             }
   1580             pollStateDone();
   1581         }
   1582 
   1583     }
   1584 
   1585     /**
   1586      * Set roaming state when cdmaRoaming is true and ons is different from spn
   1587      * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming
   1588      * @param s ServiceState hold current ons
   1589      * @return true for roaming state set
   1590      */
   1591     private boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) {
   1592         return cdmaRoaming && !isSameOperatorNameFromSimAndSS(s);
   1593     }
   1594 
   1595     void handlePollStateResultMessage(int what, AsyncResult ar) {
   1596         int ints[];
   1597         String states[];
   1598         switch (what) {
   1599             case EVENT_POLL_STATE_REGISTRATION: {
   1600                 if (mPhone.isPhoneTypeGsm()) {
   1601                     states = (String[]) ar.result;
   1602                     int lac = -1;
   1603                     int cid = -1;
   1604                     int type = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
   1605                     int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
   1606                     int reasonRegStateDenied = -1;
   1607                     int psc = -1;
   1608                     if (states.length > 0) {
   1609                         try {
   1610                             regState = Integer.parseInt(states[0]);
   1611                             if (states.length >= 3) {
   1612                                 if (states[1] != null && states[1].length() > 0) {
   1613                                     lac = Integer.parseInt(states[1], 16);
   1614                                 }
   1615                                 if (states[2] != null && states[2].length() > 0) {
   1616                                     cid = Integer.parseInt(states[2], 16);
   1617                                 }
   1618 
   1619                                 // states[3] (if present) is the current radio technology
   1620                                 if (states.length >= 4 && states[3] != null) {
   1621                                     type = Integer.parseInt(states[3]);
   1622                                 }
   1623                             }
   1624                             if (states.length > 14) {
   1625                                 if (states[14] != null && states[14].length() > 0) {
   1626                                     psc = Integer.parseInt(states[14], 16);
   1627                                 }
   1628                             }
   1629                         } catch (NumberFormatException ex) {
   1630                             loge("error parsing RegistrationState: " + ex);
   1631                         }
   1632                     }
   1633 
   1634                     mGsmRoaming = regCodeIsRoaming(regState);
   1635                     mNewSS.setVoiceRegState(regCodeToServiceState(regState));
   1636                     mNewSS.setRilVoiceRadioTechnology(type);
   1637 
   1638                     boolean isVoiceCapable = mPhone.getContext().getResources()
   1639                             .getBoolean(com.android.internal.R.bool.config_voice_capable);
   1640                     if ((regState == ServiceState.RIL_REG_STATE_DENIED_EMERGENCY_CALL_ENABLED
   1641                             || regState == ServiceState.RIL_REG_STATE_NOT_REG_EMERGENCY_CALL_ENABLED
   1642                             || regState == ServiceState.RIL_REG_STATE_SEARCHING_EMERGENCY_CALL_ENABLED
   1643                             || regState == ServiceState.RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED)
   1644                             && isVoiceCapable) {
   1645                         mEmergencyOnly = true;
   1646                     } else {
   1647                         mEmergencyOnly = false;
   1648                     }
   1649 
   1650                     // LAC and CID are -1 if not avail
   1651                     ((GsmCellLocation)mNewCellLoc).setLacAndCid(lac, cid);
   1652                     ((GsmCellLocation)mNewCellLoc).setPsc(psc);
   1653                 } else {
   1654                     states = (String[])ar.result;
   1655 
   1656                     int registrationState = 4;     //[0] registrationState
   1657                     int radioTechnology = -1;      //[3] radioTechnology
   1658                     int baseStationId = -1;        //[4] baseStationId
   1659                     //[5] baseStationLatitude
   1660                     int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG;
   1661                     //[6] baseStationLongitude
   1662                     int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
   1663                     int cssIndicator = 0;          //[7] init with 0, because it is treated as a boolean
   1664                     int systemId = 0;              //[8] systemId
   1665                     int networkId = 0;             //[9] networkId
   1666                     int roamingIndicator = -1;     //[10] Roaming indicator
   1667                     int systemIsInPrl = 0;         //[11] Indicates if current system is in PRL
   1668                     int defaultRoamingIndicator = 0;  //[12] Is default roaming indicator from PRL
   1669                     int reasonForDenial = 0;       //[13] Denial reason if registrationState = 3
   1670 
   1671                     if (states.length >= 14) {
   1672                         try {
   1673                             if (states[0] != null) {
   1674                                 registrationState = Integer.parseInt(states[0]);
   1675                             }
   1676                             if (states[3] != null) {
   1677                                 radioTechnology = Integer.parseInt(states[3]);
   1678                             }
   1679                             if (states[4] != null) {
   1680                                 baseStationId = Integer.parseInt(states[4]);
   1681                             }
   1682                             if (states[5] != null) {
   1683                                 baseStationLatitude = Integer.parseInt(states[5]);
   1684                             }
   1685                             if (states[6] != null) {
   1686                                 baseStationLongitude = Integer.parseInt(states[6]);
   1687                             }
   1688                             // Some carriers only return lat-lngs of 0,0
   1689                             if (baseStationLatitude == 0 && baseStationLongitude == 0) {
   1690                                 baseStationLatitude  = CdmaCellLocation.INVALID_LAT_LONG;
   1691                                 baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG;
   1692                             }
   1693                             if (states[7] != null) {
   1694                                 cssIndicator = Integer.parseInt(states[7]);
   1695                             }
   1696                             if (states[8] != null) {
   1697                                 systemId = Integer.parseInt(states[8]);
   1698                             }
   1699                             if (states[9] != null) {
   1700                                 networkId = Integer.parseInt(states[9]);
   1701                             }
   1702                             if (states[10] != null) {
   1703                                 roamingIndicator = Integer.parseInt(states[10]);
   1704                             }
   1705                             if (states[11] != null) {
   1706                                 systemIsInPrl = Integer.parseInt(states[11]);
   1707                             }
   1708                             if (states[12] != null) {
   1709                                 defaultRoamingIndicator = Integer.parseInt(states[12]);
   1710                             }
   1711                             if (states[13] != null) {
   1712                                 reasonForDenial = Integer.parseInt(states[13]);
   1713                             }
   1714                         } catch (NumberFormatException ex) {
   1715                             loge("EVENT_POLL_STATE_REGISTRATION_CDMA: error parsing: " + ex);
   1716                         }
   1717                     } else {
   1718                         throw new RuntimeException("Warning! Wrong number of parameters returned from "
   1719                                 + "RIL_REQUEST_REGISTRATION_STATE: expected 14 or more "
   1720                                 + "strings and got " + states.length + " strings");
   1721                     }
   1722 
   1723                     mRegistrationState = registrationState;
   1724                     // When registration state is roaming and TSB58
   1725                     // roaming indicator is not in the carrier-specified
   1726                     // list of ERIs for home system, mCdmaRoaming is true.
   1727                     boolean cdmaRoaming =
   1728                             regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
   1729                     mNewSS.setVoiceRoaming(cdmaRoaming);
   1730                     mNewSS.setVoiceRegState(regCodeToServiceState(registrationState));
   1731 
   1732                     mNewSS.setRilVoiceRadioTechnology(radioTechnology);
   1733 
   1734                     mNewSS.setCssIndicator(cssIndicator);
   1735                     mNewSS.setSystemAndNetworkId(systemId, networkId);
   1736                     mRoamingIndicator = roamingIndicator;
   1737                     mIsInPrl = (systemIsInPrl == 0) ? false : true;
   1738                     mDefaultRoamingIndicator = defaultRoamingIndicator;
   1739 
   1740 
   1741                     // Values are -1 if not available.
   1742                     ((CdmaCellLocation)mNewCellLoc).setCellLocationData(baseStationId,
   1743                             baseStationLatitude, baseStationLongitude, systemId, networkId);
   1744 
   1745                     if (reasonForDenial == 0) {
   1746                         mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_GEN;
   1747                     } else if (reasonForDenial == 1) {
   1748                         mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_AUTH;
   1749                     } else {
   1750                         mRegistrationDeniedReason = "";
   1751                     }
   1752 
   1753                     if (mRegistrationState == 3) {
   1754                         if (DBG) log("Registration denied, " + mRegistrationDeniedReason);
   1755                     }
   1756                 }
   1757                 break;
   1758             }
   1759 
   1760             case EVENT_POLL_STATE_GPRS: {
   1761                 if (mPhone.isPhoneTypeGsm()) {
   1762                     states = (String[]) ar.result;
   1763 
   1764                     int type = 0;
   1765                     int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
   1766                     mNewReasonDataDenied = -1;
   1767                     mNewMaxDataCalls = 1;
   1768                     if (states.length > 0) {
   1769                         try {
   1770                             regState = Integer.parseInt(states[0]);
   1771 
   1772                             // states[3] (if present) is the current radio technology
   1773                             if (states.length >= 4 && states[3] != null) {
   1774                                 type = Integer.parseInt(states[3]);
   1775                             }
   1776                             if ((states.length >= 5) &&
   1777                                     (regState == ServiceState.RIL_REG_STATE_DENIED)) {
   1778                                 mNewReasonDataDenied = Integer.parseInt(states[4]);
   1779                             }
   1780                             if (states.length >= 6) {
   1781                                 mNewMaxDataCalls = Integer.parseInt(states[5]);
   1782                             }
   1783                         } catch (NumberFormatException ex) {
   1784                             loge("error parsing GprsRegistrationState: " + ex);
   1785                         }
   1786                     }
   1787                     int dataRegState = regCodeToServiceState(regState);
   1788                     mNewSS.setDataRegState(dataRegState);
   1789                     mDataRoaming = regCodeIsRoaming(regState);
   1790                     mNewSS.setRilDataRadioTechnology(type);
   1791                     if (DBG) {
   1792                         log("handlPollStateResultMessage: GsmSST setDataRegState=" + dataRegState
   1793                                 + " regState=" + regState
   1794                                 + " dataRadioTechnology=" + type);
   1795                     }
   1796                 } else if (mPhone.isPhoneTypeCdma()) {
   1797                     states = (String[])ar.result;
   1798                     if (DBG) {
   1799                         log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" +
   1800                                 states.length + " states=" + states);
   1801                     }
   1802 
   1803                     int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
   1804                     int dataRadioTechnology = 0;
   1805 
   1806                     if (states.length > 0) {
   1807                         try {
   1808                             regState = Integer.parseInt(states[0]);
   1809 
   1810                             // states[3] (if present) is the current radio technology
   1811                             if (states.length >= 4 && states[3] != null) {
   1812                                 dataRadioTechnology = Integer.parseInt(states[3]);
   1813                             }
   1814                         } catch (NumberFormatException ex) {
   1815                             loge("handlePollStateResultMessage: error parsing GprsRegistrationState: "
   1816                                     + ex);
   1817                         }
   1818                     }
   1819 
   1820                     int dataRegState = regCodeToServiceState(regState);
   1821                     mNewSS.setDataRegState(dataRegState);
   1822                     mNewSS.setRilDataRadioTechnology(dataRadioTechnology);
   1823                     mNewSS.setDataRoaming(regCodeIsRoaming(regState));
   1824                     if (DBG) {
   1825                         log("handlPollStateResultMessage: cdma setDataRegState=" + dataRegState
   1826                                 + " regState=" + regState
   1827                                 + " dataRadioTechnology=" + dataRadioTechnology);
   1828                     }
   1829                 } else {
   1830                     states = (String[])ar.result;
   1831                     if (DBG) {
   1832                         log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" +
   1833                                 states.length + " states=" + states);
   1834                     }
   1835 
   1836                     int newDataRAT = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
   1837                     int regState = -1;
   1838                     if (states.length > 0) {
   1839                         try {
   1840                             regState = Integer.parseInt(states[0]);
   1841 
   1842                             // states[3] (if present) is the current radio technology
   1843                             if (states.length >= 4 && states[3] != null) {
   1844                                 newDataRAT = Integer.parseInt(states[3]);
   1845                             }
   1846                         } catch (NumberFormatException ex) {
   1847                             loge("handlePollStateResultMessage: error parsing GprsRegistrationState: "
   1848                                     + ex);
   1849                         }
   1850                     }
   1851 
   1852                     // If the unsolicited signal strength comes just before data RAT family changes
   1853                     // (i.e. from UNKNOWN to LTE, CDMA to LTE, LTE to CDMA), the signal bar might
   1854                     // display the wrong information until the next unsolicited signal strength
   1855                     // information coming from the modem, which might take a long time to come or
   1856                     // even not come at all.  In order to provide the best user experience, we
   1857                     // query the latest signal information so it will show up on the UI on time.
   1858                     int oldDataRAT = mSS.getRilDataRadioTechnology();
   1859                     if ((oldDataRAT == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN &&
   1860                             newDataRAT != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) ||
   1861                             (ServiceState.isCdma(oldDataRAT) && ServiceState.isLte(newDataRAT)) ||
   1862                             (ServiceState.isLte(oldDataRAT) && ServiceState.isCdma(newDataRAT))) {
   1863                         mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
   1864                     }
   1865 
   1866                     mNewSS.setRilDataRadioTechnology(newDataRAT);
   1867                     int dataRegState = regCodeToServiceState(regState);
   1868                     mNewSS.setDataRegState(dataRegState);
   1869                     // voice roaming state in done while handling EVENT_POLL_STATE_REGISTRATION_CDMA
   1870                     mNewSS.setDataRoaming(regCodeIsRoaming(regState));
   1871                     if (DBG) {
   1872                         log("handlPollStateResultMessage: CdmaLteSST setDataRegState=" + dataRegState
   1873                                 + " regState=" + regState
   1874                                 + " dataRadioTechnology=" + newDataRAT);
   1875                     }
   1876                 }
   1877                 break;
   1878             }
   1879 
   1880             case EVENT_POLL_STATE_OPERATOR: {
   1881                 if (mPhone.isPhoneTypeGsm()) {
   1882                     String opNames[] = (String[]) ar.result;
   1883 
   1884                     if (opNames != null && opNames.length >= 3) {
   1885                         // FIXME: Giving brandOverride higher precedence, is this desired?
   1886                         String brandOverride = mUiccController.getUiccCard(getPhoneId()) != null ?
   1887                                 mUiccController.getUiccCard(getPhoneId()).getOperatorBrandOverride() : null;
   1888                         if (brandOverride != null) {
   1889                             log("EVENT_POLL_STATE_OPERATOR: use brandOverride=" + brandOverride);
   1890                             mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]);
   1891                         } else {
   1892                             mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
   1893                         }
   1894                     }
   1895                 } else {
   1896                     String opNames[] = (String[])ar.result;
   1897 
   1898                     if (opNames != null && opNames.length >= 3) {
   1899                         // TODO: Do we care about overriding in this case.
   1900                         // If the NUMERIC field isn't valid use PROPERTY_CDMA_HOME_OPERATOR_NUMERIC
   1901                         if ((opNames[2] == null) || (opNames[2].length() < 5)
   1902                                 || ("00000".equals(opNames[2]))) {
   1903                             opNames[2] = SystemProperties.get(
   1904                                     GsmCdmaPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC, "00000");
   1905                             if (DBG) {
   1906                                 log("RIL_REQUEST_OPERATOR.response[2], the numeric, " +
   1907                                         " is bad. Using SystemProperties '" +
   1908                                         GsmCdmaPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC +
   1909                                         "'= " + opNames[2]);
   1910                             }
   1911                         }
   1912 
   1913                         if (!mIsSubscriptionFromRuim) {
   1914                             // NV device (as opposed to CSIM)
   1915                             mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
   1916                         } else {
   1917                             String brandOverride = mUiccController.getUiccCard(getPhoneId()) != null ?
   1918                                     mUiccController.getUiccCard(getPhoneId()).getOperatorBrandOverride() : null;
   1919                             if (brandOverride != null) {
   1920                                 mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]);
   1921                             } else {
   1922                                 mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
   1923                             }
   1924                         }
   1925                     } else {
   1926                         if (DBG) log("EVENT_POLL_STATE_OPERATOR_CDMA: error parsing opNames");
   1927                     }
   1928                 }
   1929                 break;
   1930             }
   1931 
   1932             case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: {
   1933                 ints = (int[])ar.result;
   1934                 mNewSS.setIsManualSelection(ints[0] == 1);
   1935                 if ((ints[0] == 1) && (!mPhone.isManualNetSelAllowed())) {
   1936                         /*
   1937                          * modem is currently in manual selection but manual
   1938                          * selection is not allowed in the current mode so
   1939                          * switch to automatic registration
   1940                          */
   1941                     mPhone.setNetworkSelectionModeAutomatic (null);
   1942                     log(" Forcing Automatic Network Selection, " +
   1943                             "manual selection is not allowed");
   1944                 }
   1945                 break;
   1946             }
   1947 
   1948             default:
   1949                 loge("handlePollStateResultMessage: Unexpected RIL response received: " + what);
   1950         }
   1951     }
   1952 
   1953     /**
   1954      * Determine whether a roaming indicator is in the carrier-specified list of ERIs for
   1955      * home system
   1956      *
   1957      * @param roamInd roaming indicator in String
   1958      * @return true if the roamInd is in the carrier-specified list of ERIs for home network
   1959      */
   1960     private boolean isRoamIndForHomeSystem(String roamInd) {
   1961         // retrieve the carrier-specified list of ERIs for home system
   1962         String[] homeRoamIndicators = mPhone.getContext().getResources()
   1963                 .getStringArray(com.android.internal.R.array.config_cdma_home_system);
   1964 
   1965         if (homeRoamIndicators != null) {
   1966             // searches through the comma-separated list for a match,
   1967             // return true if one is found.
   1968             for (String homeRoamInd : homeRoamIndicators) {
   1969                 if (homeRoamInd.equals(roamInd)) {
   1970                     return true;
   1971                 }
   1972             }
   1973             // no matches found against the list!
   1974             return false;
   1975         }
   1976 
   1977         // no system property found for the roaming indicators for home system
   1978         return false;
   1979     }
   1980 
   1981     /**
   1982      * Query the carrier configuration to determine if there any network overrides
   1983      * for roaming or not roaming for the current service state.
   1984      */
   1985     protected void updateRoamingState() {
   1986         if (mPhone.isPhoneTypeGsm()) {
   1987             /**
   1988              * Since the roaming state of gsm service (from +CREG) and
   1989              * data service (from +CGREG) could be different, the new SS
   1990              * is set to roaming when either is true.
   1991              *
   1992              * There are exceptions for the above rule.
   1993              * The new SS is not set as roaming while gsm service reports
   1994              * roaming but indeed it is same operator.
   1995              * And the operator is considered non roaming.
   1996              *
   1997              * The test for the operators is to handle special roaming
   1998              * agreements and MVNO's.
   1999              */
   2000             boolean roaming = (mGsmRoaming || mDataRoaming);
   2001             if (mGsmRoaming && !isOperatorConsideredRoaming(mNewSS) &&
   2002                     (isSameNamedOperators(mNewSS) || isOperatorConsideredNonRoaming(mNewSS))) {
   2003                 roaming = false;
   2004             }
   2005 
   2006             // Save the roaming state before carrier config possibly overrides it.
   2007             mNewSS.setDataRoamingFromRegistration(roaming);
   2008 
   2009             CarrierConfigManager configLoader = (CarrierConfigManager)
   2010                     mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
   2011 
   2012             if (configLoader != null) {
   2013                 try {
   2014                     PersistableBundle b = configLoader.getConfigForSubId(mPhone.getSubId());
   2015 
   2016                     if (alwaysOnHomeNetwork(b)) {
   2017                         log("updateRoamingState: carrier config override always on home network");
   2018                         roaming = false;
   2019                     } else if (isNonRoamingInGsmNetwork(b, mNewSS.getOperatorNumeric())) {
   2020                         log("updateRoamingState: carrier config override set non roaming:"
   2021                                 + mNewSS.getOperatorNumeric());
   2022                         roaming = false;
   2023                     } else if (isRoamingInGsmNetwork(b, mNewSS.getOperatorNumeric())) {
   2024                         log("updateRoamingState: carrier config override set roaming:"
   2025                                 + mNewSS.getOperatorNumeric());
   2026                         roaming = true;
   2027                     }
   2028                 } catch (Exception e) {
   2029                     loge("updateRoamingState: unable to access carrier config service");
   2030                 }
   2031             } else {
   2032                 log("updateRoamingState: no carrier config service available");
   2033             }
   2034 
   2035             mNewSS.setVoiceRoaming(roaming);
   2036             mNewSS.setDataRoaming(roaming);
   2037         } else {
   2038             // Save the roaming state before carrier config possibly overrides it.
   2039             mNewSS.setDataRoamingFromRegistration(mNewSS.getDataRoaming());
   2040 
   2041             CarrierConfigManager configLoader = (CarrierConfigManager)
   2042                     mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
   2043             if (configLoader != null) {
   2044                 try {
   2045                     PersistableBundle b = configLoader.getConfigForSubId(mPhone.getSubId());
   2046                     String systemId = Integer.toString(mNewSS.getSystemId());
   2047 
   2048                     if (alwaysOnHomeNetwork(b)) {
   2049                         log("updateRoamingState: carrier config override always on home network");
   2050                         setRoamingOff();
   2051                     } else if (isNonRoamingInGsmNetwork(b, mNewSS.getOperatorNumeric())
   2052                             || isNonRoamingInCdmaNetwork(b, systemId)) {
   2053                         log("updateRoamingState: carrier config override set non-roaming:"
   2054                                 + mNewSS.getOperatorNumeric() + ", " + systemId);
   2055                         setRoamingOff();
   2056                     } else if (isRoamingInGsmNetwork(b, mNewSS.getOperatorNumeric())
   2057                             || isRoamingInCdmaNetwork(b, systemId)) {
   2058                         log("updateRoamingState: carrier config override set roaming:"
   2059                                 + mNewSS.getOperatorNumeric() + ", " + systemId);
   2060                         setRoamingOn();
   2061                     }
   2062                 } catch (Exception e) {
   2063                     loge("updateRoamingState: unable to access carrier config service");
   2064                 }
   2065             } else {
   2066                 log("updateRoamingState: no carrier config service available");
   2067             }
   2068 
   2069             if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
   2070                 mNewSS.setVoiceRoaming(true);
   2071                 mNewSS.setDataRoaming(true);
   2072             }
   2073         }
   2074     }
   2075 
   2076     private void setRoamingOn() {
   2077         mNewSS.setVoiceRoaming(true);
   2078         mNewSS.setDataRoaming(true);
   2079         mNewSS.setCdmaEriIconIndex(EriInfo.ROAMING_INDICATOR_ON);
   2080         mNewSS.setCdmaEriIconMode(EriInfo.ROAMING_ICON_MODE_NORMAL);
   2081     }
   2082 
   2083     private void setRoamingOff() {
   2084         mNewSS.setVoiceRoaming(false);
   2085         mNewSS.setDataRoaming(false);
   2086         mNewSS.setCdmaEriIconIndex(EriInfo.ROAMING_INDICATOR_OFF);
   2087     }
   2088 
   2089     protected void updateSpnDisplay() {
   2090         updateOperatorNameFromEri();
   2091 
   2092         String wfcVoiceSpnFormat = null;
   2093         String wfcDataSpnFormat = null;
   2094         if (mPhone.getImsPhone() != null && mPhone.getImsPhone().isWifiCallingEnabled()) {
   2095             // In Wi-Fi Calling mode show SPN+WiFi
   2096 
   2097             String[] wfcSpnFormats = mPhone.getContext().getResources().getStringArray(
   2098                     com.android.internal.R.array.wfcSpnFormats);
   2099             int voiceIdx = 0;
   2100             int dataIdx = 0;
   2101             CarrierConfigManager configLoader = (CarrierConfigManager)
   2102                     mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
   2103             if (configLoader != null) {
   2104                 try {
   2105                     PersistableBundle b = configLoader.getConfigForSubId(mPhone.getSubId());
   2106                     if (b != null) {
   2107                         voiceIdx = b.getInt(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT);
   2108                         dataIdx = b.getInt(
   2109                                 CarrierConfigManager.KEY_WFC_DATA_SPN_FORMAT_IDX_INT);
   2110                     }
   2111                 } catch (Exception e) {
   2112                     loge("updateSpnDisplay: carrier config error: " + e);
   2113                 }
   2114             }
   2115 
   2116             wfcVoiceSpnFormat = wfcSpnFormats[voiceIdx];
   2117             wfcDataSpnFormat = wfcSpnFormats[dataIdx];
   2118         }
   2119 
   2120         if (mPhone.isPhoneTypeGsm()) {
   2121             // The values of plmn/showPlmn change in different scenarios.
   2122             // 1) No service but emergency call allowed -> expected
   2123             //    to show "Emergency call only"
   2124             //    EXTRA_SHOW_PLMN = true
   2125             //    EXTRA_PLMN = "Emergency call only"
   2126 
   2127             // 2) No service at all --> expected to show "No service"
   2128             //    EXTRA_SHOW_PLMN = true
   2129             //    EXTRA_PLMN = "No service"
   2130 
   2131             // 3) Normal operation in either home or roaming service
   2132             //    EXTRA_SHOW_PLMN = depending on IccRecords rule
   2133             //    EXTRA_PLMN = plmn
   2134 
   2135             // 4) No service due to power off, aka airplane mode
   2136             //    EXTRA_SHOW_PLMN = false
   2137             //    EXTRA_PLMN = null
   2138 
   2139             IccRecords iccRecords = mIccRecords;
   2140             String plmn = null;
   2141             boolean showPlmn = false;
   2142             int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0;
   2143             if (mSS.getVoiceRegState() == ServiceState.STATE_OUT_OF_SERVICE
   2144                     || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY) {
   2145                 showPlmn = true;
   2146                 if (mEmergencyOnly) {
   2147                     // No service but emergency call allowed
   2148                     plmn = Resources.getSystem().
   2149                             getText(com.android.internal.R.string.emergency_calls_only).toString();
   2150                 } else {
   2151                     // No service at all
   2152                     plmn = Resources.getSystem().
   2153                             getText(com.android.internal.R.string.lockscreen_carrier_default).toString();
   2154                 }
   2155                 if (DBG) log("updateSpnDisplay: radio is on but out " +
   2156                         "of service, set plmn='" + plmn + "'");
   2157             } else if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
   2158                 // In either home or roaming service
   2159                 plmn = mSS.getOperatorAlphaLong();
   2160                 showPlmn = !TextUtils.isEmpty(plmn) &&
   2161                         ((rule & SIMRecords.SPN_RULE_SHOW_PLMN)
   2162                                 == SIMRecords.SPN_RULE_SHOW_PLMN);
   2163             } else {
   2164                 // Power off state, such as airplane mode, show plmn as "No service"
   2165                 showPlmn = true;
   2166                 plmn = Resources.getSystem().
   2167                         getText(com.android.internal.R.string.lockscreen_carrier_default).toString();
   2168                 if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn="
   2169                         + showPlmn + " plmn=" + plmn);
   2170             }
   2171 
   2172             // The value of spn/showSpn are same in different scenarios.
   2173             //    EXTRA_SHOW_SPN = depending on IccRecords rule and radio/IMS state
   2174             //    EXTRA_SPN = spn
   2175             //    EXTRA_DATA_SPN = dataSpn
   2176             String spn = (iccRecords != null) ? iccRecords.getServiceProviderName() : "";
   2177             String dataSpn = spn;
   2178             boolean showSpn = !TextUtils.isEmpty(spn)
   2179                     && ((rule & SIMRecords.SPN_RULE_SHOW_SPN)
   2180                     == SIMRecords.SPN_RULE_SHOW_SPN);
   2181 
   2182             if (!TextUtils.isEmpty(spn) && !TextUtils.isEmpty(wfcVoiceSpnFormat) &&
   2183                     !TextUtils.isEmpty(wfcDataSpnFormat)) {
   2184                 // In Wi-Fi Calling mode show SPN+WiFi
   2185 
   2186                 String originalSpn = spn.trim();
   2187                 spn = String.format(wfcVoiceSpnFormat, originalSpn);
   2188                 dataSpn = String.format(wfcDataSpnFormat, originalSpn);
   2189                 showSpn = true;
   2190                 showPlmn = false;
   2191             } else if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF
   2192                     || (showPlmn && TextUtils.equals(spn, plmn))) {
   2193                 // airplane mode or spn equals plmn, do not show spn
   2194                 spn = null;
   2195                 showSpn = false;
   2196             }
   2197 
   2198             int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
   2199             int[] subIds = SubscriptionManager.getSubId(mPhone.getPhoneId());
   2200             if (subIds != null && subIds.length > 0) {
   2201                 subId = subIds[0];
   2202             }
   2203 
   2204             // Update SPN_STRINGS_UPDATED_ACTION IFF any value changes
   2205             if (mSubId != subId ||
   2206                     showPlmn != mCurShowPlmn
   2207                     || showSpn != mCurShowSpn
   2208                     || !TextUtils.equals(spn, mCurSpn)
   2209                     || !TextUtils.equals(dataSpn, mCurDataSpn)
   2210                     || !TextUtils.equals(plmn, mCurPlmn)) {
   2211                 if (DBG) {
   2212                     log(String.format("updateSpnDisplay: changed sending intent rule=" + rule +
   2213                             " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s' dataSpn='%s' " +
   2214                             "subId='%d'", showPlmn, plmn, showSpn, spn, dataSpn, subId));
   2215                 }
   2216                 Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
   2217                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   2218                 intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn);
   2219                 intent.putExtra(TelephonyIntents.EXTRA_SPN, spn);
   2220                 intent.putExtra(TelephonyIntents.EXTRA_DATA_SPN, dataSpn);
   2221                 intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
   2222                 intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
   2223                 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
   2224                 mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2225 
   2226                 if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(),
   2227                         showPlmn, plmn, showSpn, spn)) {
   2228                     mSpnUpdatePending = true;
   2229                 }
   2230             }
   2231 
   2232             mSubId = subId;
   2233             mCurShowSpn = showSpn;
   2234             mCurShowPlmn = showPlmn;
   2235             mCurSpn = spn;
   2236             mCurDataSpn = dataSpn;
   2237             mCurPlmn = plmn;
   2238         } else {
   2239             // mOperatorAlphaLong contains the ERI text
   2240             String plmn = mSS.getOperatorAlphaLong();
   2241             boolean showPlmn = false;
   2242 
   2243             showPlmn = plmn != null;
   2244 
   2245             int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
   2246             int[] subIds = SubscriptionManager.getSubId(mPhone.getPhoneId());
   2247             if (subIds != null && subIds.length > 0) {
   2248                 subId = subIds[0];
   2249             }
   2250 
   2251             if (!TextUtils.isEmpty(plmn) && !TextUtils.isEmpty(wfcVoiceSpnFormat)) {
   2252                 // In Wi-Fi Calling mode show SPN+WiFi
   2253 
   2254                 String originalPlmn = plmn.trim();
   2255                 plmn = String.format(wfcVoiceSpnFormat, originalPlmn);
   2256             } else if (mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
   2257                 // todo: temporary hack; should have a better fix. This is to avoid using operator
   2258                 // name from ServiceState (populated in resetServiceStateInIwlanMode()) until
   2259                 // wifi calling is actually enabled
   2260                 log("updateSpnDisplay: overwriting plmn from " + plmn + " to null as radio " +
   2261                         "state is off");
   2262                 plmn = null;
   2263             }
   2264 
   2265             if (mSubId != subId || !TextUtils.equals(plmn, mCurPlmn)) {
   2266                 // Allow A blank plmn, "" to set showPlmn to true. Previously, we
   2267                 // would set showPlmn to true only if plmn was not empty, i.e. was not
   2268                 // null and not blank. But this would cause us to incorrectly display
   2269                 // "No Service". Now showPlmn is set to true for any non null string.
   2270                 if (DBG) {
   2271                     log(String.format("updateSpnDisplay: changed sending intent" +
   2272                             " showPlmn='%b' plmn='%s' subId='%d'", showPlmn, plmn, subId));
   2273                 }
   2274                 Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
   2275                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   2276                 intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, false);
   2277                 intent.putExtra(TelephonyIntents.EXTRA_SPN, "");
   2278                 intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
   2279                 intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
   2280                 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
   2281                 mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2282 
   2283                 if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(),
   2284                         showPlmn, plmn, false, "")) {
   2285                     mSpnUpdatePending = true;
   2286                 }
   2287             }
   2288 
   2289             mSubId = subId;
   2290             mCurShowSpn = false;
   2291             mCurShowPlmn = showPlmn;
   2292             mCurSpn = "";
   2293             mCurPlmn = plmn;
   2294         }
   2295     }
   2296 
   2297     protected void setPowerStateToDesired() {
   2298         if (DBG) {
   2299             log("mDeviceShuttingDown=" + mDeviceShuttingDown +
   2300                     ", mDesiredPowerState=" + mDesiredPowerState +
   2301                     ", getRadioState=" + mCi.getRadioState() +
   2302                     ", mPowerOffDelayNeed=" + mPowerOffDelayNeed +
   2303                     ", mAlarmSwitch=" + mAlarmSwitch +
   2304                     ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier);
   2305         }
   2306 
   2307         if (mPhone.isPhoneTypeGsm() && mAlarmSwitch) {
   2308             if(DBG) log("mAlarmSwitch == true");
   2309             Context context = mPhone.getContext();
   2310             AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
   2311             am.cancel(mRadioOffIntent);
   2312             mAlarmSwitch = false;
   2313         }
   2314 
   2315         // If we want it on and it's off, turn it on
   2316         if (mDesiredPowerState && !mRadioDisabledByCarrier
   2317                 && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
   2318             mCi.setRadioPower(true, null);
   2319         } else if ((!mDesiredPowerState || mRadioDisabledByCarrier) && mCi.getRadioState().isOn()) {
   2320             // If it's on and available and we want it off gracefully
   2321             if (mPhone.isPhoneTypeGsm() && mPowerOffDelayNeed) {
   2322                 if (mImsRegistrationOnOff && !mAlarmSwitch) {
   2323                     if(DBG) log("mImsRegistrationOnOff == true");
   2324                     Context context = mPhone.getContext();
   2325                     AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
   2326 
   2327                     Intent intent = new Intent(ACTION_RADIO_OFF);
   2328                     mRadioOffIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
   2329 
   2330                     mAlarmSwitch = true;
   2331                     if (DBG) log("Alarm setting");
   2332                     am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
   2333                             SystemClock.elapsedRealtime() + 3000, mRadioOffIntent);
   2334                 } else {
   2335                     DcTracker dcTracker = mPhone.mDcTracker;
   2336                     powerOffRadioSafely(dcTracker);
   2337                 }
   2338             } else {
   2339                 DcTracker dcTracker = mPhone.mDcTracker;
   2340                 powerOffRadioSafely(dcTracker);
   2341             }
   2342         } else if (mDeviceShuttingDown && mCi.getRadioState().isAvailable()) {
   2343             mCi.requestShutdown(null);
   2344         }
   2345     }
   2346 
   2347     protected void onUpdateIccAvailability() {
   2348         if (mUiccController == null ) {
   2349             return;
   2350         }
   2351 
   2352         UiccCardApplication newUiccApplication = getUiccCardApplication();
   2353 
   2354         if (mUiccApplcation != newUiccApplication) {
   2355             if (mUiccApplcation != null) {
   2356                 log("Removing stale icc objects.");
   2357                 mUiccApplcation.unregisterForReady(this);
   2358                 if (mIccRecords != null) {
   2359                     mIccRecords.unregisterForRecordsLoaded(this);
   2360                 }
   2361                 mIccRecords = null;
   2362                 mUiccApplcation = null;
   2363             }
   2364             if (newUiccApplication != null) {
   2365                 log("New card found");
   2366                 mUiccApplcation = newUiccApplication;
   2367                 mIccRecords = mUiccApplcation.getIccRecords();
   2368                 if (mPhone.isPhoneTypeGsm()) {
   2369                     mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);
   2370                     if (mIccRecords != null) {
   2371                         mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
   2372                     }
   2373                 } else if (mIsSubscriptionFromRuim) {
   2374                     mUiccApplcation.registerForReady(this, EVENT_RUIM_READY, null);
   2375                     if (mIccRecords != null) {
   2376                         mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
   2377                     }
   2378                 }
   2379             }
   2380         }
   2381     }
   2382 
   2383     protected void log(String s) {
   2384         Rlog.d(LOG_TAG, s);
   2385     }
   2386 
   2387     protected void loge(String s) {
   2388         Rlog.e(LOG_TAG, s);
   2389     }
   2390 
   2391     /**
   2392      * @return The current GPRS state. IN_SERVICE is the same as "attached"
   2393      * and OUT_OF_SERVICE is the same as detached.
   2394      */
   2395     public int getCurrentDataConnectionState() {
   2396         return mSS.getDataRegState();
   2397     }
   2398 
   2399     /**
   2400      * @return true if phone is camping on a technology (eg UMTS)
   2401      * that could support voice and data simultaneously.
   2402      */
   2403     public boolean isConcurrentVoiceAndDataAllowed() {
   2404         if (mPhone.isPhoneTypeGsm()) {
   2405             return (mSS.getRilVoiceRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
   2406         } else if (mPhone.isPhoneTypeCdma()) {
   2407             // Note: it needs to be confirmed which CDMA network types
   2408             // can support voice and data calls concurrently.
   2409             // For the time-being, the return value will be false.
   2410             return false;
   2411         } else {
   2412             // Using the Conncurrent Service Supported flag for CdmaLte devices.
   2413             return mSS.getCssIndicator() == 1;
   2414         }
   2415     }
   2416 
   2417     public void setImsRegistrationState(boolean registered) {
   2418         log("ImsRegistrationState - registered : " + registered);
   2419 
   2420         if (mImsRegistrationOnOff && !registered) {
   2421             if (mAlarmSwitch) {
   2422                 mImsRegistrationOnOff = registered;
   2423 
   2424                 Context context = mPhone.getContext();
   2425                 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
   2426                 am.cancel(mRadioOffIntent);
   2427                 mAlarmSwitch = false;
   2428 
   2429                 sendMessage(obtainMessage(EVENT_CHANGE_IMS_STATE));
   2430                 return;
   2431             }
   2432         }
   2433         mImsRegistrationOnOff = registered;
   2434     }
   2435 
   2436     public void onImsCapabilityChanged() {
   2437         sendMessage(obtainMessage(EVENT_IMS_CAPABILITY_CHANGED));
   2438     }
   2439 
   2440     public boolean isRadioOn() {
   2441         return mCi.getRadioState() == CommandsInterface.RadioState.RADIO_ON;
   2442     }
   2443 
   2444     /**
   2445      * A complete "service state" from our perspective is
   2446      * composed of a handful of separate requests to the radio.
   2447      *
   2448      * We make all of these requests at once, but then abandon them
   2449      * and start over again if the radio notifies us that some
   2450      * event has changed
   2451      */
   2452     public void pollState() {
   2453         pollState(false);
   2454     }
   2455     /**
   2456      * We insist on polling even if the radio says its off.
   2457      * Used when we get a network changed notification
   2458      * but the radio is off - part of iwlan hack
   2459      */
   2460     private void modemTriggeredPollState() {
   2461         pollState(true);
   2462     }
   2463 
   2464     public void pollState(boolean modemTriggered) {
   2465         mPollingContext = new int[1];
   2466         mPollingContext[0] = 0;
   2467 
   2468         switch (mCi.getRadioState()) {
   2469             case RADIO_UNAVAILABLE:
   2470                 mNewSS.setStateOutOfService();
   2471                 mNewCellLoc.setStateInvalid();
   2472                 setSignalStrengthDefaultValues();
   2473                 mGotCountryCode = false;
   2474                 mNitzUpdatedTime = false;
   2475                 pollStateDone();
   2476                 break;
   2477 
   2478             case RADIO_OFF:
   2479                 mNewSS.setStateOff();
   2480                 mNewCellLoc.setStateInvalid();
   2481                 setSignalStrengthDefaultValues();
   2482                 mGotCountryCode = false;
   2483                 mNitzUpdatedTime = false;
   2484                 // don't poll for state when the radio is off
   2485                 // EXCEPT, if the poll was modemTrigged (they sent us new radio data)
   2486                 // or we're on IWLAN
   2487                 if (!modemTriggered && ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
   2488                         != mSS.getRilDataRadioTechnology()) {
   2489                     pollStateDone();
   2490                     break;
   2491                 }
   2492 
   2493             default:
   2494                 // Issue all poll-related commands at once then count down the responses, which
   2495                 // are allowed to arrive out-of-order
   2496                 mPollingContext[0]++;
   2497                 mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR, mPollingContext));
   2498 
   2499                 mPollingContext[0]++;
   2500                 mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, mPollingContext));
   2501 
   2502                 mPollingContext[0]++;
   2503                 mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION,
   2504                         mPollingContext));
   2505 
   2506                 if (mPhone.isPhoneTypeGsm()) {
   2507                     mPollingContext[0]++;
   2508                     mCi.getNetworkSelectionMode(obtainMessage(
   2509                             EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));
   2510                 }
   2511                 break;
   2512         }
   2513     }
   2514 
   2515     //todo: try to merge pollstate functions
   2516     private void pollStateDone() {
   2517         if (mPhone.isPhoneTypeGsm()) {
   2518             pollStateDoneGsm();
   2519         } else if (mPhone.isPhoneTypeCdma()) {
   2520             pollStateDoneCdma();
   2521         } else {
   2522             pollStateDoneCdmaLte();
   2523         }
   2524     }
   2525 
   2526     private void pollStateDoneGsm() {
   2527         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
   2528             mNewSS.setVoiceRoaming(true);
   2529             mNewSS.setDataRoaming(true);
   2530         }
   2531         useDataRegStateForDataOnlyDevices();
   2532         resetServiceStateInIwlanMode();
   2533 
   2534         if (DBG) {
   2535             log("Poll ServiceState done: " +
   2536                     " oldSS=[" + mSS + "] newSS=[" + mNewSS + "]" +
   2537                     " oldMaxDataCalls=" + mMaxDataCalls +
   2538                     " mNewMaxDataCalls=" + mNewMaxDataCalls +
   2539                     " oldReasonDataDenied=" + mReasonDataDenied +
   2540                     " mNewReasonDataDenied=" + mNewReasonDataDenied);
   2541         }
   2542 
   2543         boolean hasRegistered =
   2544                 mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
   2545                         && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
   2546 
   2547         boolean hasDeregistered =
   2548                 mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
   2549                         && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
   2550 
   2551         boolean hasGprsAttached =
   2552                 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
   2553                         && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
   2554 
   2555         boolean hasGprsDetached =
   2556                 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
   2557                         && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
   2558 
   2559         boolean hasDataRegStateChanged =
   2560                 mSS.getDataRegState() != mNewSS.getDataRegState();
   2561 
   2562         boolean hasVoiceRegStateChanged =
   2563                 mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
   2564 
   2565         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
   2566 
   2567         // ratchet the new tech up through it's rat family but don't drop back down
   2568         // until cell change
   2569         if (hasLocationChanged == false) {
   2570             mRatRatcheter.ratchetRat(mSS, mNewSS);
   2571         }
   2572 
   2573         boolean hasRilVoiceRadioTechnologyChanged =
   2574                 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
   2575 
   2576         boolean hasRilDataRadioTechnologyChanged =
   2577                 mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
   2578 
   2579         boolean hasChanged = !mNewSS.equals(mSS);
   2580 
   2581         boolean hasVoiceRoamingOn = !mSS.getVoiceRoaming() && mNewSS.getVoiceRoaming();
   2582 
   2583         boolean hasVoiceRoamingOff = mSS.getVoiceRoaming() && !mNewSS.getVoiceRoaming();
   2584 
   2585         boolean hasDataRoamingOn = !mSS.getDataRoaming() && mNewSS.getDataRoaming();
   2586 
   2587         boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming();
   2588 
   2589         TelephonyManager tm =
   2590                 (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
   2591 
   2592         // Add an event log when connection state changes
   2593         if (hasVoiceRegStateChanged || hasDataRegStateChanged) {
   2594             EventLog.writeEvent(EventLogTags.GSM_SERVICE_STATE_CHANGE,
   2595                     mSS.getVoiceRegState(), mSS.getDataRegState(),
   2596                     mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
   2597         }
   2598 
   2599         // Add an event log when network type switched
   2600         // TODO: we may add filtering to reduce the event logged,
   2601         // i.e. check preferred network setting, only switch to 2G, etc
   2602         if (hasRilVoiceRadioTechnologyChanged) {
   2603             int cid = -1;
   2604             GsmCellLocation loc = (GsmCellLocation)mNewCellLoc;
   2605             if (loc != null) cid = loc.getCid();
   2606             // NOTE: this code was previously located after mSS and mNewSS are swapped, so
   2607             // existing logs were incorrectly using the new state for "network_from"
   2608             // and STATE_OUT_OF_SERVICE for "network_to". To avoid confusion, use a new log tag
   2609             // to record the correct states.
   2610             EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED_NEW, cid,
   2611                     mSS.getRilVoiceRadioTechnology(),
   2612                     mNewSS.getRilVoiceRadioTechnology());
   2613             if (DBG) {
   2614                 log("RAT switched "
   2615                         + ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology())
   2616                         + " -> "
   2617                         + ServiceState.rilRadioTechnologyToString(
   2618                         mNewSS.getRilVoiceRadioTechnology()) + " at cell " + cid);
   2619             }
   2620         }
   2621 
   2622         // swap mSS and mNewSS to put new state in mSS
   2623         ServiceState tss = mSS;
   2624         mSS = mNewSS;
   2625         mNewSS = tss;
   2626         // clean slate for next time
   2627         mNewSS.setStateOutOfService();
   2628 
   2629         // swap mCellLoc and mNewCellLoc to put new state in mCellLoc
   2630         GsmCellLocation tcl = (GsmCellLocation)mCellLoc;
   2631         mCellLoc = mNewCellLoc;
   2632         mNewCellLoc = tcl;
   2633 
   2634         mReasonDataDenied = mNewReasonDataDenied;
   2635         mMaxDataCalls = mNewMaxDataCalls;
   2636 
   2637         if (hasRilVoiceRadioTechnologyChanged) {
   2638             updatePhoneObject();
   2639         }
   2640 
   2641         if (hasRilDataRadioTechnologyChanged) {
   2642             tm.setDataNetworkTypeForPhone(mPhone.getPhoneId(), mSS.getRilDataRadioTechnology());
   2643 
   2644             if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
   2645                     == mSS.getRilDataRadioTechnology()) {
   2646                 log("pollStateDone: IWLAN enabled");
   2647             }
   2648         }
   2649 
   2650         if (hasRegistered) {
   2651             mNetworkAttachedRegistrants.notifyRegistrants();
   2652 
   2653             if (DBG) {
   2654                 log("pollStateDone: registering current mNitzUpdatedTime=" +
   2655                         mNitzUpdatedTime + " changing to false");
   2656             }
   2657             mNitzUpdatedTime = false;
   2658         }
   2659 
   2660         if (hasChanged) {
   2661             String operatorNumeric;
   2662 
   2663             updateSpnDisplay();
   2664 
   2665             tm.setNetworkOperatorNameForPhone(mPhone.getPhoneId(), mSS.getOperatorAlphaLong());
   2666 
   2667             String prevOperatorNumeric = tm.getNetworkOperatorForPhone(mPhone.getPhoneId());
   2668             operatorNumeric = mSS.getOperatorNumeric();
   2669             tm.setNetworkOperatorNumericForPhone(mPhone.getPhoneId(), operatorNumeric);
   2670             updateCarrierMccMncConfiguration(operatorNumeric,
   2671                     prevOperatorNumeric, mPhone.getContext());
   2672             if (operatorNumeric == null) {
   2673                 if (DBG) log("operatorNumeric is null");
   2674                 tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), "");
   2675                 mGotCountryCode = false;
   2676                 mNitzUpdatedTime = false;
   2677             } else {
   2678                 String iso = "";
   2679                 String mcc = "";
   2680                 try{
   2681                     mcc = operatorNumeric.substring(0, 3);
   2682                     iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc));
   2683                 } catch ( NumberFormatException ex){
   2684                     loge("pollStateDone: countryCodeForMcc error" + ex);
   2685                 } catch ( StringIndexOutOfBoundsException ex) {
   2686                     loge("pollStateDone: countryCodeForMcc error" + ex);
   2687                 }
   2688 
   2689                 tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), iso);
   2690                 mGotCountryCode = true;
   2691 
   2692                 TimeZone zone = null;
   2693 
   2694                 if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) &&
   2695                         getAutoTimeZone()) {
   2696 
   2697                     // Test both paths if ignore nitz is true
   2698                     boolean testOneUniqueOffsetPath = SystemProperties.getBoolean(
   2699                             TelephonyProperties.PROPERTY_IGNORE_NITZ, false) &&
   2700                             ((SystemClock.uptimeMillis() & 1) == 0);
   2701 
   2702                     ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso);
   2703                     if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) {
   2704                         zone = uniqueZones.get(0);
   2705                         if (DBG) {
   2706                             log("pollStateDone: no nitz but one TZ for iso-cc=" + iso +
   2707                                     " with zone.getID=" + zone.getID() +
   2708                                     " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
   2709                         }
   2710                         setAndBroadcastNetworkSetTimeZone(zone.getID());
   2711                     } else {
   2712                         if (DBG) {
   2713                             log("pollStateDone: there are " + uniqueZones.size() +
   2714                                     " unique offsets for iso-cc='" + iso +
   2715                                     " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath +
   2716                                     "', do nothing");
   2717                         }
   2718                     }
   2719                 }
   2720 
   2721                 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
   2722                         mNeedFixZoneAfterNitz)) {
   2723                     fixTimeZone(iso);
   2724                 }
   2725             }
   2726 
   2727             tm.setNetworkRoamingForPhone(mPhone.getPhoneId(), mSS.getVoiceRoaming());
   2728 
   2729             setRoamingType(mSS);
   2730             log("Broadcasting ServiceState : " + mSS);
   2731             mPhone.notifyServiceStateChanged(mSS);
   2732 
   2733             mEventLog.writeServiceStateChanged(mSS);
   2734         }
   2735 
   2736         if (hasGprsAttached) {
   2737             mAttachedRegistrants.notifyRegistrants();
   2738         }
   2739 
   2740         if (hasGprsDetached) {
   2741             mDetachedRegistrants.notifyRegistrants();
   2742         }
   2743 
   2744         if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
   2745             notifyDataRegStateRilRadioTechnologyChanged();
   2746 
   2747             if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
   2748                     == mSS.getRilDataRadioTechnology()) {
   2749                 mPhone.notifyDataConnection(Phone.REASON_IWLAN_AVAILABLE);
   2750             } else {
   2751                 mPhone.notifyDataConnection(null);
   2752             }
   2753         }
   2754 
   2755         if (hasVoiceRoamingOn) {
   2756             mVoiceRoamingOnRegistrants.notifyRegistrants();
   2757         }
   2758 
   2759         if (hasVoiceRoamingOff) {
   2760             mVoiceRoamingOffRegistrants.notifyRegistrants();
   2761         }
   2762 
   2763         if (hasDataRoamingOn) {
   2764             mDataRoamingOnRegistrants.notifyRegistrants();
   2765         }
   2766 
   2767         if (hasDataRoamingOff) {
   2768             mDataRoamingOffRegistrants.notifyRegistrants();
   2769         }
   2770 
   2771         if (hasLocationChanged) {
   2772             mPhone.notifyLocationChanged();
   2773         }
   2774 
   2775         if (!isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
   2776             if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
   2777                 mStartedGprsRegCheck = true;
   2778 
   2779                 int check_period = Settings.Global.getInt(
   2780                         mPhone.getContext().getContentResolver(),
   2781                         Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
   2782                         DEFAULT_GPRS_CHECK_PERIOD_MILLIS);
   2783                 sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS),
   2784                         check_period);
   2785             }
   2786         } else {
   2787             mReportedGprsNoReg = false;
   2788         }
   2789     }
   2790 
   2791     protected void pollStateDoneCdma() {
   2792         updateRoamingState();
   2793 
   2794         useDataRegStateForDataOnlyDevices();
   2795         resetServiceStateInIwlanMode();
   2796         if (DBG) log("pollStateDone: cdma oldSS=[" + mSS + "] newSS=[" + mNewSS + "]");
   2797 
   2798         boolean hasRegistered =
   2799                 mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
   2800                         && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
   2801 
   2802         boolean hasCdmaDataConnectionAttached =
   2803                 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
   2804                         && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
   2805 
   2806         boolean hasCdmaDataConnectionDetached =
   2807                 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
   2808                         && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
   2809 
   2810         boolean hasCdmaDataConnectionChanged =
   2811                 mSS.getDataRegState() != mNewSS.getDataRegState();
   2812 
   2813         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
   2814 
   2815         // ratchet the new tech up through it's rat family but don't drop back down
   2816         // until cell change
   2817         if (hasLocationChanged == false) {
   2818             mRatRatcheter.ratchetRat(mSS, mNewSS);
   2819         }
   2820 
   2821         boolean hasRilVoiceRadioTechnologyChanged =
   2822                 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
   2823 
   2824         boolean hasRilDataRadioTechnologyChanged =
   2825                 mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
   2826 
   2827         boolean hasChanged = !mNewSS.equals(mSS);
   2828 
   2829         boolean hasVoiceRoamingOn = !mSS.getVoiceRoaming() && mNewSS.getVoiceRoaming();
   2830 
   2831         boolean hasVoiceRoamingOff = mSS.getVoiceRoaming() && !mNewSS.getVoiceRoaming();
   2832 
   2833         boolean hasDataRoamingOn = !mSS.getDataRoaming() && mNewSS.getDataRoaming();
   2834 
   2835         boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming();
   2836 
   2837         TelephonyManager tm =
   2838                 (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
   2839 
   2840         // Add an event log when connection state changes
   2841         if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState() ||
   2842                 mSS.getDataRegState() != mNewSS.getDataRegState()) {
   2843             EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE,
   2844                     mSS.getVoiceRegState(), mSS.getDataRegState(),
   2845                     mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
   2846         }
   2847 
   2848         ServiceState tss;
   2849         tss = mSS;
   2850         mSS = mNewSS;
   2851         mNewSS = tss;
   2852         // clean slate for next time
   2853         mNewSS.setStateOutOfService();
   2854 
   2855         CdmaCellLocation tcl = (CdmaCellLocation)mCellLoc;
   2856         mCellLoc = mNewCellLoc;
   2857         mNewCellLoc = tcl;
   2858 
   2859         if (hasRilVoiceRadioTechnologyChanged) {
   2860             updatePhoneObject();
   2861         }
   2862 
   2863         if (hasRilDataRadioTechnologyChanged) {
   2864             tm.setDataNetworkTypeForPhone(mPhone.getPhoneId(), mSS.getRilDataRadioTechnology());
   2865 
   2866             if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
   2867                     == mSS.getRilDataRadioTechnology()) {
   2868                 log("pollStateDone: IWLAN enabled");
   2869             }
   2870         }
   2871 
   2872         if (hasRegistered) {
   2873             mNetworkAttachedRegistrants.notifyRegistrants();
   2874         }
   2875 
   2876         if (hasChanged) {
   2877             updateSpnDisplay();
   2878 
   2879             String operatorNumeric;
   2880 
   2881             tm.setNetworkOperatorNameForPhone(mPhone.getPhoneId(), mSS.getOperatorAlphaLong());
   2882 
   2883             String prevOperatorNumeric = tm.getNetworkOperatorForPhone(mPhone.getPhoneId());
   2884             operatorNumeric = mSS.getOperatorNumeric();
   2885 
   2886             // try to fix the invalid Operator Numeric
   2887             if (isInvalidOperatorNumeric(operatorNumeric)) {
   2888                 int sid = mSS.getSystemId();
   2889                 operatorNumeric = fixUnknownMcc(operatorNumeric, sid);
   2890             }
   2891 
   2892             tm.setNetworkOperatorNumericForPhone(mPhone.getPhoneId(), operatorNumeric);
   2893             updateCarrierMccMncConfiguration(operatorNumeric,
   2894                     prevOperatorNumeric, mPhone.getContext());
   2895 
   2896             if (isInvalidOperatorNumeric(operatorNumeric)) {
   2897                 if (DBG) log("operatorNumeric "+ operatorNumeric +"is invalid");
   2898                 tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), "");
   2899                 mGotCountryCode = false;
   2900             } else {
   2901                 String isoCountryCode = "";
   2902                 String mcc = operatorNumeric.substring(0, 3);
   2903                 try{
   2904                     isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(
   2905                             operatorNumeric.substring(0, 3)));
   2906                 } catch ( NumberFormatException ex){
   2907                     loge("pollStateDone: countryCodeForMcc error" + ex);
   2908                 } catch ( StringIndexOutOfBoundsException ex) {
   2909                     loge("pollStateDone: countryCodeForMcc error" + ex);
   2910                 }
   2911 
   2912                 tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), isoCountryCode);
   2913                 mGotCountryCode = true;
   2914 
   2915                 setOperatorIdd(operatorNumeric);
   2916 
   2917                 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
   2918                         mNeedFixZoneAfterNitz)) {
   2919                     fixTimeZone(isoCountryCode);
   2920                 }
   2921             }
   2922 
   2923             tm.setNetworkRoamingForPhone(mPhone.getPhoneId(),
   2924                     (mSS.getVoiceRoaming() || mSS.getDataRoaming()));
   2925 
   2926             // set roaming type
   2927             setRoamingType(mSS);
   2928             log("Broadcasting ServiceState : " + mSS);
   2929             mPhone.notifyServiceStateChanged(mSS);
   2930         }
   2931 
   2932         if (hasCdmaDataConnectionAttached) {
   2933             mAttachedRegistrants.notifyRegistrants();
   2934         }
   2935 
   2936         if (hasCdmaDataConnectionDetached) {
   2937             mDetachedRegistrants.notifyRegistrants();
   2938         }
   2939 
   2940         if (hasCdmaDataConnectionChanged || hasRilDataRadioTechnologyChanged) {
   2941             notifyDataRegStateRilRadioTechnologyChanged();
   2942             if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
   2943                     == mSS.getRilDataRadioTechnology()) {
   2944                 mPhone.notifyDataConnection(Phone.REASON_IWLAN_AVAILABLE);
   2945             } else {
   2946                 mPhone.notifyDataConnection(null);
   2947             }
   2948         }
   2949 
   2950         if (hasVoiceRoamingOn) {
   2951             mVoiceRoamingOnRegistrants.notifyRegistrants();
   2952         }
   2953 
   2954         if (hasVoiceRoamingOff) {
   2955             mVoiceRoamingOffRegistrants.notifyRegistrants();
   2956         }
   2957 
   2958         if (hasDataRoamingOn) {
   2959             mDataRoamingOnRegistrants.notifyRegistrants();
   2960         }
   2961 
   2962         if (hasDataRoamingOff) {
   2963             mDataRoamingOffRegistrants.notifyRegistrants();
   2964         }
   2965 
   2966         if (hasLocationChanged) {
   2967             mPhone.notifyLocationChanged();
   2968         }
   2969         // TODO: Add CdmaCellIdenity updating, see CdmaLteServiceStateTracker.
   2970     }
   2971 
   2972     protected void pollStateDoneCdmaLte() {
   2973         updateRoamingState();
   2974 
   2975         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
   2976             mNewSS.setVoiceRoaming(true);
   2977             mNewSS.setDataRoaming(true);
   2978         }
   2979 
   2980         useDataRegStateForDataOnlyDevices();
   2981         resetServiceStateInIwlanMode();
   2982         log("pollStateDone: lte 1 ss=[" + mSS + "] newSS=[" + mNewSS + "]");
   2983 
   2984         boolean hasRegistered = mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
   2985                 && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
   2986 
   2987         boolean hasDeregistered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
   2988                 && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
   2989 
   2990         boolean hasCdmaDataConnectionAttached =
   2991                 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
   2992                         && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
   2993 
   2994         boolean hasCdmaDataConnectionDetached =
   2995                 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
   2996                         && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
   2997 
   2998         boolean hasCdmaDataConnectionChanged =
   2999                 mSS.getDataRegState() != mNewSS.getDataRegState();
   3000 
   3001         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
   3002 
   3003         // ratchet the new tech up through it's rat family but don't drop back down
   3004         // until cell change
   3005         if (hasLocationChanged == false) {
   3006             mRatRatcheter.ratchetRat(mSS, mNewSS);
   3007         }
   3008 
   3009         boolean hasVoiceRadioTechnologyChanged = mSS.getRilVoiceRadioTechnology()
   3010                 != mNewSS.getRilVoiceRadioTechnology();
   3011 
   3012         boolean hasDataRadioTechnologyChanged = mSS.getRilDataRadioTechnology()
   3013                 != mNewSS.getRilDataRadioTechnology();
   3014 
   3015         boolean hasChanged = !mNewSS.equals(mSS);
   3016 
   3017         boolean hasVoiceRoamingOn = !mSS.getVoiceRoaming() && mNewSS.getVoiceRoaming();
   3018 
   3019         boolean hasVoiceRoamingOff = mSS.getVoiceRoaming() && !mNewSS.getVoiceRoaming();
   3020 
   3021         boolean hasDataRoamingOn = !mSS.getDataRoaming() && mNewSS.getDataRoaming();
   3022 
   3023         boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming();
   3024 
   3025         boolean has4gHandoff =
   3026                 mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE &&
   3027                 ((ServiceState.isLte(mSS.getRilDataRadioTechnology()) &&
   3028                 (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) ||
   3029                 ((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD) &&
   3030                 ServiceState.isLte(mNewSS.getRilDataRadioTechnology())));
   3031 
   3032         boolean hasMultiApnSupport =
   3033                 ((ServiceState.isLte(mNewSS.getRilDataRadioTechnology()) ||
   3034                 (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) &&
   3035                 (!ServiceState.isLte(mSS.getRilDataRadioTechnology()) &&
   3036                 (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)));
   3037 
   3038         boolean hasLostMultiApnSupport =
   3039                 ((mNewSS.getRilDataRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A) &&
   3040                 (mNewSS.getRilDataRadioTechnology() <= ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A));
   3041 
   3042         TelephonyManager tm =
   3043                 (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
   3044 
   3045         if (DBG) {
   3046             log("pollStateDone:"
   3047                     + " hasRegistered=" + hasRegistered
   3048                     + " hasDeegistered=" + hasDeregistered
   3049                     + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached
   3050                     + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached
   3051                     + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged
   3052                     + " hasVoiceRadioTechnologyChanged= " + hasVoiceRadioTechnologyChanged
   3053                     + " hasDataRadioTechnologyChanged=" + hasDataRadioTechnologyChanged
   3054                     + " hasChanged=" + hasChanged
   3055                     + " hasVoiceRoamingOn=" + hasVoiceRoamingOn
   3056                     + " hasVoiceRoamingOff=" + hasVoiceRoamingOff
   3057                     + " hasDataRoamingOn=" + hasDataRoamingOn
   3058                     + " hasDataRoamingOff=" + hasDataRoamingOff
   3059                     + " hasLocationChanged=" + hasLocationChanged
   3060                     + " has4gHandoff = " + has4gHandoff
   3061                     + " hasMultiApnSupport=" + hasMultiApnSupport
   3062                     + " hasLostMultiApnSupport=" + hasLostMultiApnSupport);
   3063         }
   3064         // Add an event log when connection state changes
   3065         if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState()
   3066                 || mSS.getDataRegState() != mNewSS.getDataRegState()) {
   3067             EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, mSS.getVoiceRegState(),
   3068                     mSS.getDataRegState(), mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
   3069         }
   3070 
   3071         ServiceState tss;
   3072         tss = mSS;
   3073         mSS = mNewSS;
   3074         mNewSS = tss;
   3075         // clean slate for next time
   3076         mNewSS.setStateOutOfService();
   3077 
   3078         CdmaCellLocation tcl = (CdmaCellLocation)mCellLoc;
   3079         mCellLoc = mNewCellLoc;
   3080         mNewCellLoc = tcl;
   3081 
   3082         mNewSS.setStateOutOfService(); // clean slate for next time
   3083 
   3084         if (hasVoiceRadioTechnologyChanged) {
   3085             updatePhoneObject();
   3086         }
   3087 
   3088         if (hasDataRadioTechnologyChanged) {
   3089             tm.setDataNetworkTypeForPhone(mPhone.getPhoneId(), mSS.getRilDataRadioTechnology());
   3090 
   3091             if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
   3092                     == mSS.getRilDataRadioTechnology()) {
   3093                 log("pollStateDone: IWLAN enabled");
   3094             }
   3095         }
   3096 
   3097         if (hasRegistered) {
   3098             mNetworkAttachedRegistrants.notifyRegistrants();
   3099         }
   3100 
   3101         if (hasChanged) {
   3102             updateSpnDisplay();
   3103 
   3104             String operatorNumeric;
   3105 
   3106             tm.setNetworkOperatorNameForPhone(mPhone.getPhoneId(), mSS.getOperatorAlphaLong());
   3107 
   3108             String prevOperatorNumeric = tm.getNetworkOperatorForPhone(mPhone.getPhoneId());
   3109             operatorNumeric = mSS.getOperatorNumeric();
   3110             // try to fix the invalid Operator Numeric
   3111             if (isInvalidOperatorNumeric(operatorNumeric)) {
   3112                 int sid = mSS.getSystemId();
   3113                 operatorNumeric = fixUnknownMcc(operatorNumeric, sid);
   3114             }
   3115             tm.setNetworkOperatorNumericForPhone(mPhone.getPhoneId(), operatorNumeric);
   3116             updateCarrierMccMncConfiguration(operatorNumeric,
   3117                     prevOperatorNumeric, mPhone.getContext());
   3118 
   3119             if (isInvalidOperatorNumeric(operatorNumeric)) {
   3120                 if (DBG) log("operatorNumeric is null");
   3121                 tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), "");
   3122                 mGotCountryCode = false;
   3123             } else {
   3124                 String isoCountryCode = "";
   3125                 String mcc = operatorNumeric.substring(0, 3);
   3126                 try {
   3127                     isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric
   3128                             .substring(0, 3)));
   3129                 } catch (NumberFormatException ex) {
   3130                     loge("countryCodeForMcc error" + ex);
   3131                 } catch (StringIndexOutOfBoundsException ex) {
   3132                     loge("countryCodeForMcc error" + ex);
   3133                 }
   3134 
   3135                 tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), isoCountryCode);
   3136                 mGotCountryCode = true;
   3137 
   3138                 setOperatorIdd(operatorNumeric);
   3139 
   3140                 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
   3141                         mNeedFixZoneAfterNitz)) {
   3142                     fixTimeZone(isoCountryCode);
   3143                 }
   3144             }
   3145 
   3146             tm.setNetworkRoamingForPhone(mPhone.getPhoneId(),
   3147                     (mSS.getVoiceRoaming() || mSS.getDataRoaming()));
   3148 
   3149             setRoamingType(mSS);
   3150             log("Broadcasting ServiceState : " + mSS);
   3151             mPhone.notifyServiceStateChanged(mSS);
   3152         }
   3153 
   3154         if (hasCdmaDataConnectionAttached || has4gHandoff) {
   3155             mAttachedRegistrants.notifyRegistrants();
   3156         }
   3157 
   3158         if (hasCdmaDataConnectionDetached) {
   3159             mDetachedRegistrants.notifyRegistrants();
   3160         }
   3161 
   3162         if ((hasCdmaDataConnectionChanged || hasDataRadioTechnologyChanged)) {
   3163             notifyDataRegStateRilRadioTechnologyChanged();
   3164             if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
   3165                     == mSS.getRilDataRadioTechnology()) {
   3166                 mPhone.notifyDataConnection(Phone.REASON_IWLAN_AVAILABLE);
   3167             } else {
   3168                 mPhone.notifyDataConnection(null);
   3169             }
   3170         }
   3171 
   3172         if (hasVoiceRoamingOn) {
   3173             mVoiceRoamingOnRegistrants.notifyRegistrants();
   3174         }
   3175 
   3176         if (hasVoiceRoamingOff) {
   3177             mVoiceRoamingOffRegistrants.notifyRegistrants();
   3178         }
   3179 
   3180         if (hasDataRoamingOn) {
   3181             mDataRoamingOnRegistrants.notifyRegistrants();
   3182         }
   3183 
   3184         if (hasDataRoamingOff) {
   3185             mDataRoamingOffRegistrants.notifyRegistrants();
   3186         }
   3187 
   3188         if (hasLocationChanged) {
   3189             mPhone.notifyLocationChanged();
   3190         }
   3191     }
   3192 
   3193     private void updateOperatorNameFromEri() {
   3194         if (mPhone.isPhoneTypeCdma()) {
   3195             if ((mCi.getRadioState().isOn()) && (!mIsSubscriptionFromRuim)) {
   3196                 String eriText;
   3197                 // Now the Phone sees the new ServiceState so it can get the new ERI text
   3198                 if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
   3199                     eriText = mPhone.getCdmaEriText();
   3200                 } else {
   3201                     // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used for
   3202                     // mRegistrationState 0,2,3 and 4
   3203                     eriText = mPhone.getContext().getText(
   3204                             com.android.internal.R.string.roamingTextSearching).toString();
   3205                 }
   3206                 mSS.setOperatorAlphaLong(eriText);
   3207             }
   3208         } else if (mPhone.isPhoneTypeCdmaLte()) {
   3209             boolean hasBrandOverride = mUiccController.getUiccCard(getPhoneId()) != null &&
   3210                     mUiccController.getUiccCard(getPhoneId()).getOperatorBrandOverride() != null;
   3211             if (!hasBrandOverride && (mCi.getRadioState().isOn()) && (mPhone.isEriFileLoaded()) &&
   3212                     (!ServiceState.isLte(mSS.getRilVoiceRadioTechnology()) ||
   3213                             mPhone.getContext().getResources().getBoolean(com.android.internal.R.
   3214                                     bool.config_LTE_eri_for_network_name))) {
   3215                 // Only when CDMA is in service, ERI will take effect
   3216                 String eriText = mSS.getOperatorAlphaLong();
   3217                 // Now the Phone sees the new ServiceState so it can get the new ERI text
   3218                 if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
   3219                     eriText = mPhone.getCdmaEriText();
   3220                 } else if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF) {
   3221                     eriText = (mIccRecords != null) ? mIccRecords.getServiceProviderName() : null;
   3222                     if (TextUtils.isEmpty(eriText)) {
   3223                         // Sets operator alpha property by retrieving from
   3224                         // build-time system property
   3225                         eriText = SystemProperties.get("ro.cdma.home.operator.alpha");
   3226                     }
   3227                 } else if (mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE) {
   3228                     // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used
   3229                     // for mRegistrationState 0,2,3 and 4
   3230                     eriText = mPhone.getContext()
   3231                             .getText(com.android.internal.R.string.roamingTextSearching).toString();
   3232                 }
   3233                 mSS.setOperatorAlphaLong(eriText);
   3234             }
   3235 
   3236             if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY &&
   3237                     mIccRecords != null && (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE)
   3238                     && !ServiceState.isLte(mSS.getRilVoiceRadioTechnology())) {
   3239                 // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches
   3240                 // one configured in SIM, use operator name from CSIM record. Note that ERI, SID,
   3241                 // and NID are CDMA only, not applicable to LTE.
   3242                 boolean showSpn =
   3243                         ((RuimRecords) mIccRecords).getCsimSpnDisplayCondition();
   3244                 int iconIndex = mSS.getCdmaEriIconIndex();
   3245 
   3246                 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) &&
   3247                         isInHomeSidNid(mSS.getSystemId(), mSS.getNetworkId()) &&
   3248                         mIccRecords != null) {
   3249                     mSS.setOperatorAlphaLong(mIccRecords.getServiceProviderName());
   3250                 }
   3251             }
   3252         }
   3253     }
   3254 
   3255     /**
   3256      * Check whether the specified SID and NID pair appears in the HOME SID/NID list
   3257      * read from NV or SIM.
   3258      *
   3259      * @return true if provided sid/nid pair belongs to operator's home network.
   3260      */
   3261     private boolean isInHomeSidNid(int sid, int nid) {
   3262         // if SID/NID is not available, assume this is home network.
   3263         if (isSidsAllZeros()) return true;
   3264 
   3265         // length of SID/NID shold be same
   3266         if (mHomeSystemId.length != mHomeNetworkId.length) return true;
   3267 
   3268         if (sid == 0) return true;
   3269 
   3270         for (int i = 0; i < mHomeSystemId.length; i++) {
   3271             // Use SID only if NID is a reserved value.
   3272             // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2)
   3273             if ((mHomeSystemId[i] == sid) &&
   3274                     ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) ||
   3275                             (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) {
   3276                 return true;
   3277             }
   3278         }
   3279         // SID/NID are not in the list. So device is not in home network
   3280         return false;
   3281     }
   3282 
   3283     protected void setOperatorIdd(String operatorNumeric) {
   3284         // Retrieve the current country information
   3285         // with the MCC got from opeatorNumeric.
   3286         String idd = mHbpcdUtils.getIddByMcc(
   3287                 Integer.parseInt(operatorNumeric.substring(0,3)));
   3288         if (idd != null && !idd.isEmpty()) {
   3289             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING,
   3290                     idd);
   3291         } else {
   3292             // use default "+", since we don't know the current IDP
   3293             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING, "+");
   3294         }
   3295     }
   3296 
   3297     protected boolean isInvalidOperatorNumeric(String operatorNumeric) {
   3298         return operatorNumeric == null || operatorNumeric.length() < 5 ||
   3299                 operatorNumeric.startsWith(INVALID_MCC);
   3300     }
   3301 
   3302     protected String fixUnknownMcc(String operatorNumeric, int sid) {
   3303         if (sid <= 0) {
   3304             // no cdma information is available, do nothing
   3305             return operatorNumeric;
   3306         }
   3307 
   3308         // resolve the mcc from sid;
   3309         // if mSavedTimeZone is null, TimeZone would get the default timeZone,
   3310         // and the fixTimeZone couldn't help, because it depends on operator Numeric;
   3311         // if the sid is conflict and timezone is unavailable, the mcc may be not right.
   3312         boolean isNitzTimeZone = false;
   3313         int timeZone = 0;
   3314         TimeZone tzone = null;
   3315         if (mSavedTimeZone != null) {
   3316             timeZone =
   3317                     TimeZone.getTimeZone(mSavedTimeZone).getRawOffset()/MS_PER_HOUR;
   3318             isNitzTimeZone = true;
   3319         } else {
   3320             tzone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
   3321             if (tzone != null)
   3322                 timeZone = tzone.getRawOffset()/MS_PER_HOUR;
   3323         }
   3324 
   3325         int mcc = mHbpcdUtils.getMcc(sid,
   3326                 timeZone, (mZoneDst ? 1 : 0), isNitzTimeZone);
   3327         if (mcc > 0) {
   3328             operatorNumeric = Integer.toString(mcc) + DEFAULT_MNC;
   3329         }
   3330         return operatorNumeric;
   3331     }
   3332 
   3333     protected void fixTimeZone(String isoCountryCode) {
   3334         TimeZone zone = null;
   3335         // If the offset is (0, false) and the time zone property
   3336         // is set, use the time zone property rather than GMT.
   3337         String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
   3338         if (DBG) {
   3339             log("fixTimeZone zoneName='" + zoneName +
   3340                     "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
   3341                     " iso-cc='" + isoCountryCode +
   3342                     "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode));
   3343         }
   3344         if ("".equals(isoCountryCode) && mNeedFixZoneAfterNitz) {
   3345             // Country code not found.  This is likely a test network.
   3346             // Get a TimeZone based only on the NITZ parameters (best guess).
   3347             zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
   3348             if (DBG) log("pollStateDone: using NITZ TimeZone");
   3349         } else if ((mZoneOffset == 0) && (mZoneDst == false) && (zoneName != null)
   3350                 && (zoneName.length() > 0)
   3351                 && (Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode) < 0)) {
   3352             // For NITZ string without time zone,
   3353             // need adjust time to reflect default time zone setting
   3354             zone = TimeZone.getDefault();
   3355             if (mNeedFixZoneAfterNitz) {
   3356                 long ctm = System.currentTimeMillis();
   3357                 long tzOffset = zone.getOffset(ctm);
   3358                 if (DBG) {
   3359                     log("fixTimeZone: tzOffset=" + tzOffset +
   3360                             " ltod=" + TimeUtils.logTimeOfDay(ctm));
   3361                 }
   3362                 if (getAutoTime()) {
   3363                     long adj = ctm - tzOffset;
   3364                     if (DBG) log("fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj));
   3365                     setAndBroadcastNetworkSetTime(adj);
   3366                 } else {
   3367                     // Adjust the saved NITZ time to account for tzOffset.
   3368                     mSavedTime = mSavedTime - tzOffset;
   3369                     if (DBG) log("fixTimeZone: adj mSavedTime=" + mSavedTime);
   3370                 }
   3371             }
   3372             if (DBG) log("fixTimeZone: using default TimeZone");
   3373         } else {
   3374             zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, isoCountryCode);
   3375             if (DBG) log("fixTimeZone: using getTimeZone(off, dst, time, iso)");
   3376         }
   3377 
   3378         mNeedFixZoneAfterNitz = false;
   3379 
   3380         if (zone != null) {
   3381             log("fixTimeZone: zone != null zone.getID=" + zone.getID());
   3382             if (getAutoTimeZone()) {
   3383                 setAndBroadcastNetworkSetTimeZone(zone.getID());
   3384             } else {
   3385                 log("fixTimeZone: skip changing zone as getAutoTimeZone was false");
   3386             }
   3387             saveNitzTimeZone(zone.getID());
   3388         } else {
   3389             log("fixTimeZone: zone == null, do nothing for zone");
   3390         }
   3391     }
   3392 
   3393     /**
   3394      * Check if GPRS got registered while voice is registered.
   3395      *
   3396      * @param dataRegState i.e. CGREG in GSM
   3397      * @param voiceRegState i.e. CREG in GSM
   3398      * @return false if device only register to voice but not gprs
   3399      */
   3400     private boolean isGprsConsistent(int dataRegState, int voiceRegState) {
   3401         return !((voiceRegState == ServiceState.STATE_IN_SERVICE) &&
   3402                 (dataRegState != ServiceState.STATE_IN_SERVICE));
   3403     }
   3404 
   3405     /**
   3406      * Returns a TimeZone object based only on parameters from the NITZ string.
   3407      */
   3408     private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
   3409         TimeZone guess = findTimeZone(offset, dst, when);
   3410         if (guess == null) {
   3411             // Couldn't find a proper timezone.  Perhaps the DST data is wrong.
   3412             guess = findTimeZone(offset, !dst, when);
   3413         }
   3414         if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID()));
   3415         return guess;
   3416     }
   3417 
   3418     private TimeZone findTimeZone(int offset, boolean dst, long when) {
   3419         int rawOffset = offset;
   3420         if (dst) {
   3421             rawOffset -= MS_PER_HOUR;
   3422         }
   3423         String[] zones = TimeZone.getAvailableIDs(rawOffset);
   3424         TimeZone guess = null;
   3425         Date d = new Date(when);
   3426         for (String zone : zones) {
   3427             TimeZone tz = TimeZone.getTimeZone(zone);
   3428             if (tz.getOffset(when) == offset &&
   3429                     tz.inDaylightTime(d) == dst) {
   3430                 guess = tz;
   3431                 break;
   3432             }
   3433         }
   3434 
   3435         return guess;
   3436     }
   3437 
   3438     /** code is registration state 0-5 from TS 27.007 7.2 */
   3439     private int regCodeToServiceState(int code) {
   3440         switch (code) {
   3441             case 0:
   3442             case 2: // 2 is "searching"
   3443             case 3: // 3 is "registration denied"
   3444             case 4: // 4 is "unknown" no vaild in current baseband
   3445             case 10:// same as 0, but indicates that emergency call is possible.
   3446             case 12:// same as 2, but indicates that emergency call is possible.
   3447             case 13:// same as 3, but indicates that emergency call is possible.
   3448             case 14:// same as 4, but indicates that emergency call is possible.
   3449                 return ServiceState.STATE_OUT_OF_SERVICE;
   3450 
   3451             case 1:
   3452             case 5: // 5 is "registered, roaming"
   3453                 return ServiceState.STATE_IN_SERVICE;
   3454 
   3455             default:
   3456                 loge("regCodeToServiceState: unexpected service state " + code);
   3457                 return ServiceState.STATE_OUT_OF_SERVICE;
   3458         }
   3459     }
   3460 
   3461     /**
   3462      * code is registration state 0-5 from TS 27.007 7.2
   3463      * returns true if registered roam, false otherwise
   3464      */
   3465     private boolean regCodeIsRoaming (int code) {
   3466         return ServiceState.RIL_REG_STATE_ROAMING == code;
   3467     }
   3468 
   3469     private boolean isSameOperatorNameFromSimAndSS(ServiceState s) {
   3470         String spn = ((TelephonyManager) mPhone.getContext().
   3471                 getSystemService(Context.TELEPHONY_SERVICE)).
   3472                 getSimOperatorNameForPhone(getPhoneId());
   3473 
   3474         // NOTE: in case of RUIM we should completely ignore the ERI data file and
   3475         // mOperatorAlphaLong is set from RIL_REQUEST_OPERATOR response 0 (alpha ONS)
   3476         String onsl = s.getOperatorAlphaLong();
   3477         String onss = s.getOperatorAlphaShort();
   3478 
   3479         boolean equalsOnsl = !TextUtils.isEmpty(spn) && spn.equalsIgnoreCase(onsl);
   3480         boolean equalsOnss = !TextUtils.isEmpty(spn) && spn.equalsIgnoreCase(onss);
   3481 
   3482         return (equalsOnsl || equalsOnss);
   3483     }
   3484 
   3485     /**
   3486      * Set roaming state if operator mcc is the same as sim mcc
   3487      * and ons is not different from spn
   3488      *
   3489      * @param s ServiceState hold current ons
   3490      * @return true if same operator
   3491      */
   3492     private boolean isSameNamedOperators(ServiceState s) {
   3493         return currentMccEqualsSimMcc(s) && isSameOperatorNameFromSimAndSS(s);
   3494     }
   3495 
   3496     /**
   3497      * Compare SIM MCC with Operator MCC
   3498      *
   3499      * @param s ServiceState hold current ons
   3500      * @return true if both are same
   3501      */
   3502     private boolean currentMccEqualsSimMcc(ServiceState s) {
   3503         String simNumeric = ((TelephonyManager) mPhone.getContext().
   3504                 getSystemService(Context.TELEPHONY_SERVICE)).
   3505                 getSimOperatorNumericForPhone(getPhoneId());
   3506         String operatorNumeric = s.getOperatorNumeric();
   3507         boolean equalsMcc = true;
   3508 
   3509         try {
   3510             equalsMcc = simNumeric.substring(0, 3).
   3511                     equals(operatorNumeric.substring(0, 3));
   3512         } catch (Exception e){
   3513         }
   3514         return equalsMcc;
   3515     }
   3516 
   3517     /**
   3518      * Do not set roaming state in case of oprators considered non-roaming.
   3519      *
   3520      * Can use mcc or mcc+mnc as item of config_operatorConsideredNonRoaming.
   3521      * For example, 302 or 21407. If mcc or mcc+mnc match with operator,
   3522      * don't set roaming state.
   3523      *
   3524      * @param s ServiceState hold current ons
   3525      * @return false for roaming state set
   3526      */
   3527     private boolean isOperatorConsideredNonRoaming(ServiceState s) {
   3528         String operatorNumeric = s.getOperatorNumeric();
   3529         String[] numericArray = mPhone.getContext().getResources().getStringArray(
   3530                 com.android.internal.R.array.config_operatorConsideredNonRoaming);
   3531 
   3532         if (numericArray.length == 0 || operatorNumeric == null) {
   3533             return false;
   3534         }
   3535 
   3536         for (String numeric : numericArray) {
   3537             if (operatorNumeric.startsWith(numeric)) {
   3538                 return true;
   3539             }
   3540         }
   3541         return false;
   3542     }
   3543 
   3544     private boolean isOperatorConsideredRoaming(ServiceState s) {
   3545         String operatorNumeric = s.getOperatorNumeric();
   3546         String[] numericArray = mPhone.getContext().getResources().getStringArray(
   3547                 com.android.internal.R.array.config_sameNamedOperatorConsideredRoaming);
   3548 
   3549         if (numericArray.length == 0 || operatorNumeric == null) {
   3550             return false;
   3551         }
   3552 
   3553         for (String numeric : numericArray) {
   3554             if (operatorNumeric.startsWith(numeric)) {
   3555                 return true;
   3556             }
   3557         }
   3558         return false;
   3559     }
   3560 
   3561     /**
   3562      * Set restricted state based on the OnRestrictedStateChanged notification
   3563      * If any voice or packet restricted state changes, trigger a UI
   3564      * notification and notify registrants when sim is ready.
   3565      *
   3566      * @param ar an int value of RIL_RESTRICTED_STATE_*
   3567      */
   3568     private void onRestrictedStateChanged(AsyncResult ar) {
   3569         RestrictedState newRs = new RestrictedState();
   3570 
   3571         if (DBG) log("onRestrictedStateChanged: E rs "+ mRestrictedState);
   3572 
   3573         if (ar.exception == null) {
   3574             int[] ints = (int[])ar.result;
   3575             int state = ints[0];
   3576 
   3577             newRs.setCsEmergencyRestricted(
   3578                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
   3579                             ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
   3580             //ignore the normal call and data restricted state before SIM READY
   3581             if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY) {
   3582                 newRs.setCsNormalRestricted(
   3583                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
   3584                                 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
   3585                 newRs.setPsRestricted(
   3586                         (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0);
   3587             }
   3588 
   3589             if (DBG) log("onRestrictedStateChanged: new rs "+ newRs);
   3590 
   3591             if (!mRestrictedState.isPsRestricted() && newRs.isPsRestricted()) {
   3592                 mPsRestrictEnabledRegistrants.notifyRegistrants();
   3593                 setNotification(PS_ENABLED);
   3594             } else if (mRestrictedState.isPsRestricted() && !newRs.isPsRestricted()) {
   3595                 mPsRestrictDisabledRegistrants.notifyRegistrants();
   3596                 setNotification(PS_DISABLED);
   3597             }
   3598 
   3599             /**
   3600              * There are two kind of cs restriction, normal and emergency. So
   3601              * there are 4 x 4 combinations in current and new restricted states
   3602              * and we only need to notify when state is changed.
   3603              */
   3604             if (mRestrictedState.isCsRestricted()) {
   3605                 if (!newRs.isCsRestricted()) {
   3606                     // remove all restriction
   3607                     setNotification(CS_DISABLED);
   3608                 } else if (!newRs.isCsNormalRestricted()) {
   3609                     // remove normal restriction
   3610                     setNotification(CS_EMERGENCY_ENABLED);
   3611                 } else if (!newRs.isCsEmergencyRestricted()) {
   3612                     // remove emergency restriction
   3613                     setNotification(CS_NORMAL_ENABLED);
   3614                 }
   3615             } else if (mRestrictedState.isCsEmergencyRestricted() &&
   3616                     !mRestrictedState.isCsNormalRestricted()) {
   3617                 if (!newRs.isCsRestricted()) {
   3618                     // remove all restriction
   3619                     setNotification(CS_DISABLED);
   3620                 } else if (newRs.isCsRestricted()) {
   3621                     // enable all restriction
   3622                     setNotification(CS_ENABLED);
   3623                 } else if (newRs.isCsNormalRestricted()) {
   3624                     // remove emergency restriction and enable normal restriction
   3625                     setNotification(CS_NORMAL_ENABLED);
   3626                 }
   3627             } else if (!mRestrictedState.isCsEmergencyRestricted() &&
   3628                     mRestrictedState.isCsNormalRestricted()) {
   3629                 if (!newRs.isCsRestricted()) {
   3630                     // remove all restriction
   3631                     setNotification(CS_DISABLED);
   3632                 } else if (newRs.isCsRestricted()) {
   3633                     // enable all restriction
   3634                     setNotification(CS_ENABLED);
   3635                 } else if (newRs.isCsEmergencyRestricted()) {
   3636                     // remove normal restriction and enable emergency restriction
   3637                     setNotification(CS_EMERGENCY_ENABLED);
   3638                 }
   3639             } else {
   3640                 if (newRs.isCsRestricted()) {
   3641                     // enable all restriction
   3642                     setNotification(CS_ENABLED);
   3643                 } else if (newRs.isCsEmergencyRestricted()) {
   3644                     // enable emergency restriction
   3645                     setNotification(CS_EMERGENCY_ENABLED);
   3646                 } else if (newRs.isCsNormalRestricted()) {
   3647                     // enable normal restriction
   3648                     setNotification(CS_NORMAL_ENABLED);
   3649                 }
   3650             }
   3651 
   3652             mRestrictedState = newRs;
   3653         }
   3654         log("onRestrictedStateChanged: X rs "+ mRestrictedState);
   3655     }
   3656 
   3657     /**
   3658      * @return the current cell location information. Prefer Gsm location
   3659      * information if available otherwise return LTE location information
   3660      */
   3661     public CellLocation getCellLocation() {
   3662         if (((GsmCellLocation)mCellLoc).getLac() >= 0 &&
   3663                 ((GsmCellLocation)mCellLoc).getCid() >= 0) {
   3664             if (DBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc);
   3665             return mCellLoc;
   3666         } else {
   3667             List<CellInfo> result = getAllCellInfo();
   3668             if (result != null) {
   3669                 // A hack to allow tunneling of LTE information via GsmCellLocation
   3670                 // so that older Network Location Providers can return some information
   3671                 // on LTE only networks, see bug 9228974.
   3672                 //
   3673                 // We'll search the return CellInfo array preferring GSM/WCDMA
   3674                 // data, but if there is none we'll tunnel the first LTE information
   3675                 // in the list.
   3676                 //
   3677                 // The tunnel'd LTE information is returned as follows:
   3678                 //   LAC = TAC field
   3679                 //   CID = CI field
   3680                 //   PSC = 0.
   3681                 GsmCellLocation cellLocOther = new GsmCellLocation();
   3682                 for (CellInfo ci : result) {
   3683                     if (ci instanceof CellInfoGsm) {
   3684                         CellInfoGsm cellInfoGsm = (CellInfoGsm)ci;
   3685                         CellIdentityGsm cellIdentityGsm = cellInfoGsm.getCellIdentity();
   3686                         cellLocOther.setLacAndCid(cellIdentityGsm.getLac(),
   3687                                 cellIdentityGsm.getCid());
   3688                         cellLocOther.setPsc(cellIdentityGsm.getPsc());
   3689                         if (DBG) log("getCellLocation(): X ret GSM info=" + cellLocOther);
   3690                         return cellLocOther;
   3691                     } else if (ci instanceof CellInfoWcdma) {
   3692                         CellInfoWcdma cellInfoWcdma = (CellInfoWcdma)ci;
   3693                         CellIdentityWcdma cellIdentityWcdma = cellInfoWcdma.getCellIdentity();
   3694                         cellLocOther.setLacAndCid(cellIdentityWcdma.getLac(),
   3695                                 cellIdentityWcdma.getCid());
   3696                         cellLocOther.setPsc(cellIdentityWcdma.getPsc());
   3697                         if (DBG) log("getCellLocation(): X ret WCDMA info=" + cellLocOther);
   3698                         return cellLocOther;
   3699                     } else if ((ci instanceof CellInfoLte) &&
   3700                             ((cellLocOther.getLac() < 0) || (cellLocOther.getCid() < 0))) {
   3701                         // We'll return the first good LTE info we get if there is no better answer
   3702                         CellInfoLte cellInfoLte = (CellInfoLte)ci;
   3703                         CellIdentityLte cellIdentityLte = cellInfoLte.getCellIdentity();
   3704                         if ((cellIdentityLte.getTac() != Integer.MAX_VALUE)
   3705                                 && (cellIdentityLte.getCi() != Integer.MAX_VALUE)) {
   3706                             cellLocOther.setLacAndCid(cellIdentityLte.getTac(),
   3707                                     cellIdentityLte.getCi());
   3708                             cellLocOther.setPsc(0);
   3709                             if (DBG) {
   3710                                 log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther);
   3711                             }
   3712                         }
   3713                     }
   3714                 }
   3715                 if (DBG) {
   3716                     log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther);
   3717                 }
   3718                 return cellLocOther;
   3719             } else {
   3720                 if (DBG) {
   3721                     log("getCellLocation(): X empty mCellLoc and CellInfo mCellLoc=" + mCellLoc);
   3722                 }
   3723                 return mCellLoc;
   3724             }
   3725         }
   3726     }
   3727 
   3728     /**
   3729      * nitzReceiveTime is time_t that the NITZ time was posted
   3730      */
   3731     private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {
   3732         // "yy/mm/dd,hh:mm:ss(+/-)tz"
   3733         // tz is in number of quarter-hours
   3734 
   3735         long start = SystemClock.elapsedRealtime();
   3736         if (DBG) {log("NITZ: " + nitz + "," + nitzReceiveTime +
   3737                 " start=" + start + " delay=" + (start - nitzReceiveTime));
   3738         }
   3739 
   3740         try {
   3741             /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
   3742              * offset as well (which we won't worry about until later) */
   3743             Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
   3744 
   3745             c.clear();
   3746             c.set(Calendar.DST_OFFSET, 0);
   3747 
   3748             String[] nitzSubs = nitz.split("[/:,+-]");
   3749 
   3750             int year = 2000 + Integer.parseInt(nitzSubs[0]);
   3751             if (year > MAX_NITZ_YEAR) {
   3752                 if (DBG) loge("NITZ year: " + year + " exceeds limit, skip NITZ time update");
   3753                 return;
   3754             }
   3755             c.set(Calendar.YEAR, year);
   3756 
   3757             // month is 0 based!
   3758             int month = Integer.parseInt(nitzSubs[1]) - 1;
   3759             c.set(Calendar.MONTH, month);
   3760 
   3761             int date = Integer.parseInt(nitzSubs[2]);
   3762             c.set(Calendar.DATE, date);
   3763 
   3764             int hour = Integer.parseInt(nitzSubs[3]);
   3765             c.set(Calendar.HOUR, hour);
   3766 
   3767             int minute = Integer.parseInt(nitzSubs[4]);
   3768             c.set(Calendar.MINUTE, minute);
   3769 
   3770             int second = Integer.parseInt(nitzSubs[5]);
   3771             c.set(Calendar.SECOND, second);
   3772 
   3773             boolean sign = (nitz.indexOf('-') == -1);
   3774 
   3775             int tzOffset = Integer.parseInt(nitzSubs[6]);
   3776 
   3777             int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7]) : 0;
   3778 
   3779             // The zone offset received from NITZ is for current local time,
   3780             // so DST correction is already applied.  Don't add it again.
   3781             //
   3782             // tzOffset += dst * 4;
   3783             //
   3784             // We could unapply it if we wanted the raw offset.
   3785 
   3786             tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
   3787 
   3788             TimeZone    zone = null;
   3789 
   3790             // As a special extension, the Android emulator appends the name of
   3791             // the host computer's timezone to the nitz string. this is zoneinfo
   3792             // timezone name of the form Area!Location or Area!Location!SubLocation
   3793             // so we need to convert the ! into /
   3794             if (nitzSubs.length >= 9) {
   3795                 String  tzname = nitzSubs[8].replace('!','/');
   3796                 zone = TimeZone.getTimeZone( tzname );
   3797             }
   3798 
   3799             String iso = ((TelephonyManager) mPhone.getContext().
   3800                     getSystemService(Context.TELEPHONY_SERVICE)).
   3801                     getNetworkCountryIsoForPhone(mPhone.getPhoneId());
   3802 
   3803             if (zone == null) {
   3804 
   3805                 if (mGotCountryCode) {
   3806                     if (iso != null && iso.length() > 0) {
   3807                         zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
   3808                                 c.getTimeInMillis(),
   3809                                 iso);
   3810                     } else {
   3811                         // We don't have a valid iso country code.  This is
   3812                         // most likely because we're on a test network that's
   3813                         // using a bogus MCC (eg, "001"), so get a TimeZone
   3814                         // based only on the NITZ parameters.
   3815                         zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
   3816                     }
   3817                 }
   3818             }
   3819 
   3820             if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){
   3821                 // We got the time before the country or the zone has changed
   3822                 // so we don't know how to identify the DST rules yet.  Save
   3823                 // the information and hope to fix it up later.
   3824 
   3825                 mNeedFixZoneAfterNitz = true;
   3826                 mZoneOffset  = tzOffset;
   3827                 mZoneDst     = dst != 0;
   3828                 mZoneTime    = c.getTimeInMillis();
   3829             }
   3830             if (DBG) {
   3831                 log("NITZ: tzOffset=" + tzOffset + " dst=" + dst + " zone=" +
   3832                         (zone!=null ? zone.getID() : "NULL") +
   3833                         " iso=" + iso + " mGotCountryCode=" + mGotCountryCode +
   3834                         " mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz);
   3835             }
   3836 
   3837             if (zone != null) {
   3838                 if (getAutoTimeZone()) {
   3839                     setAndBroadcastNetworkSetTimeZone(zone.getID());
   3840                 }
   3841                 saveNitzTimeZone(zone.getID());
   3842             }
   3843 
   3844             String ignore = SystemProperties.get("gsm.ignore-nitz");
   3845             if (ignore != null && ignore.equals("yes")) {
   3846                 log("NITZ: Not setting clock because gsm.ignore-nitz is set");
   3847                 return;
   3848             }
   3849 
   3850             try {
   3851                 mWakeLock.acquire();
   3852 
   3853                 if (!mPhone.isPhoneTypeGsm() || getAutoTime()) {
   3854                     long millisSinceNitzReceived
   3855                             = SystemClock.elapsedRealtime() - nitzReceiveTime;
   3856 
   3857                     if (millisSinceNitzReceived < 0) {
   3858                         // Sanity check: something is wrong
   3859                         if (DBG) {
   3860                             log("NITZ: not setting time, clock has rolled "
   3861                                     + "backwards since NITZ time was received, "
   3862                                     + nitz);
   3863                         }
   3864                         return;
   3865                     }
   3866 
   3867                     if (millisSinceNitzReceived > Integer.MAX_VALUE) {
   3868                         // If the time is this far off, something is wrong > 24 days!
   3869                         if (DBG) {
   3870                             log("NITZ: not setting time, processing has taken "
   3871                                     + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
   3872                                     + " days");
   3873                         }
   3874                         return;
   3875                     }
   3876 
   3877                     // Note: with range checks above, cast to int is safe
   3878                     c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
   3879 
   3880                     if (DBG) {
   3881                         log("NITZ: Setting time of day to " + c.getTime()
   3882                                 + " NITZ receive delay(ms): " + millisSinceNitzReceived
   3883                                 + " gained(ms): "
   3884                                 + (c.getTimeInMillis() - System.currentTimeMillis())
   3885                                 + " from " + nitz);
   3886                     }
   3887                     if (mPhone.isPhoneTypeGsm()) {
   3888                         setAndBroadcastNetworkSetTime(c.getTimeInMillis());
   3889                         Rlog.i(LOG_TAG, "NITZ: after Setting time of day");
   3890                     } else {
   3891                         if (getAutoTime()) {
   3892                             /**
   3893                              * Update system time automatically
   3894                              */
   3895                             long gained = c.getTimeInMillis() - System.currentTimeMillis();
   3896                             long timeSinceLastUpdate = SystemClock.elapsedRealtime() - mSavedAtTime;
   3897                             int nitzUpdateSpacing = Settings.Global.getInt(mCr,
   3898                                     Settings.Global.NITZ_UPDATE_SPACING, mNitzUpdateSpacing);
   3899                             int nitzUpdateDiff = Settings.Global.getInt(mCr,
   3900                                     Settings.Global.NITZ_UPDATE_DIFF, mNitzUpdateDiff);
   3901 
   3902                             if ((mSavedAtTime == 0) || (timeSinceLastUpdate > nitzUpdateSpacing)
   3903                                     || (Math.abs(gained) > nitzUpdateDiff)) {
   3904                                 if (DBG) {
   3905                                     log("NITZ: Auto updating time of day to " + c.getTime()
   3906                                             + " NITZ receive delay=" + millisSinceNitzReceived
   3907                                             + "ms gained=" + gained + "ms from " + nitz);
   3908                                 }
   3909 
   3910                                 setAndBroadcastNetworkSetTime(c.getTimeInMillis());
   3911                             } else {
   3912                                 if (DBG) {
   3913                                     log("NITZ: ignore, a previous update was "
   3914                                             + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms");
   3915                                 }
   3916                                 return;
   3917                             }
   3918                         }
   3919                     }
   3920                 }
   3921                 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
   3922                 saveNitzTime(c.getTimeInMillis());
   3923                 mNitzUpdatedTime = true;
   3924             } finally {
   3925                 if (DBG) {
   3926                     long end = SystemClock.elapsedRealtime();
   3927                     log("NITZ: end=" + end + " dur=" + (end - start));
   3928                 }
   3929                 mWakeLock.release();
   3930             }
   3931         } catch (RuntimeException ex) {
   3932             loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
   3933         }
   3934     }
   3935 
   3936     private boolean getAutoTime() {
   3937         try {
   3938             return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME) > 0;
   3939         } catch (Settings.SettingNotFoundException snfe) {
   3940             return true;
   3941         }
   3942     }
   3943 
   3944     private boolean getAutoTimeZone() {
   3945         try {
   3946             return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE) > 0;
   3947         } catch (Settings.SettingNotFoundException snfe) {
   3948             return true;
   3949         }
   3950     }
   3951 
   3952     private void saveNitzTimeZone(String zoneId) {
   3953         mSavedTimeZone = zoneId;
   3954     }
   3955 
   3956     private void saveNitzTime(long time) {
   3957         mSavedTime = time;
   3958         mSavedAtTime = SystemClock.elapsedRealtime();
   3959     }
   3960 
   3961     /**
   3962      * Set the timezone and send out a sticky broadcast so the system can
   3963      * determine if the timezone was set by the carrier.
   3964      *
   3965      * @param zoneId timezone set by carrier
   3966      */
   3967     private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
   3968         if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId);
   3969         AlarmManager alarm =
   3970                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
   3971         alarm.setTimeZone(zoneId);
   3972         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
   3973         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   3974         intent.putExtra("time-zone", zoneId);
   3975         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   3976         if (DBG) {
   3977             log("setAndBroadcastNetworkSetTimeZone: call alarm.setTimeZone and broadcast zoneId=" +
   3978                     zoneId);
   3979         }
   3980     }
   3981 
   3982     /**
   3983      * Set the time and Send out a sticky broadcast so the system can determine
   3984      * if the time was set by the carrier.
   3985      *
   3986      * @param time time set by network
   3987      */
   3988     private void setAndBroadcastNetworkSetTime(long time) {
   3989         if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
   3990         SystemClock.setCurrentTimeMillis(time);
   3991         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
   3992         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   3993         intent.putExtra("time", time);
   3994         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   3995     }
   3996 
   3997     private void revertToNitzTime() {
   3998         if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME, 0) == 0) {
   3999             return;
   4000         }
   4001         if (DBG) {
   4002             log("Reverting to NITZ Time: mSavedTime=" + mSavedTime + " mSavedAtTime=" +
   4003                     mSavedAtTime);
   4004         }
   4005         if (mSavedTime != 0 && mSavedAtTime != 0) {
   4006             setAndBroadcastNetworkSetTime(mSavedTime
   4007                     + (SystemClock.elapsedRealtime() - mSavedAtTime));
   4008         }
   4009     }
   4010 
   4011     private void revertToNitzTimeZone() {
   4012         if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 0) == 0) {
   4013             return;
   4014         }
   4015         if (DBG) log("Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);
   4016         if (mSavedTimeZone != null) {
   4017             setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
   4018         }
   4019     }
   4020 
   4021     /**
   4022      * Post a notification to NotificationManager for restricted state
   4023      *
   4024      * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE
   4025      */
   4026     private void setNotification(int notifyType) {
   4027         if (DBG) log("setNotification: create notification " + notifyType);
   4028 
   4029         // Needed because sprout RIL sends these when they shouldn't?
   4030         boolean isSetNotification = mPhone.getContext().getResources().getBoolean(
   4031                 com.android.internal.R.bool.config_user_notification_of_restrictied_mobile_access);
   4032         if (!isSetNotification) {
   4033             if (DBG) log("Ignore all the notifications");
   4034             return;
   4035         }
   4036 
   4037         Context context = mPhone.getContext();
   4038 
   4039 
   4040         CharSequence details = "";
   4041         CharSequence title = context.getText(com.android.internal.R.string.RestrictedOnData);
   4042         int notificationId = CS_NOTIFICATION;
   4043 
   4044         switch (notifyType) {
   4045             case PS_ENABLED:
   4046                 long dataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
   4047                 if (dataSubId != mPhone.getSubId()) {
   4048                     return;
   4049                 }
   4050                 notificationId = PS_NOTIFICATION;
   4051                 details = context.getText(com.android.internal.R.string.RestrictedOnData);
   4052                 break;
   4053             case PS_DISABLED:
   4054                 notificationId = PS_NOTIFICATION;
   4055                 break;
   4056             case CS_ENABLED:
   4057                 details = context.getText(com.android.internal.R.string.RestrictedOnAllVoice);
   4058                 break;
   4059             case CS_NORMAL_ENABLED:
   4060                 details = context.getText(com.android.internal.R.string.RestrictedOnNormal);
   4061                 break;
   4062             case CS_EMERGENCY_ENABLED:
   4063                 details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);
   4064                 break;
   4065             case CS_DISABLED:
   4066                 // do nothing and cancel the notification later
   4067                 break;
   4068         }
   4069 
   4070         if (DBG) log("setNotification: put notification " + title + " / " +details);
   4071         mNotification = new Notification.Builder(context)
   4072                 .setWhen(System.currentTimeMillis())
   4073                 .setAutoCancel(true)
   4074                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
   4075                 .setTicker(title)
   4076                 .setColor(context.getResources().getColor(
   4077                         com.android.internal.R.color.system_notification_accent_color))
   4078                 .setContentTitle(title)
   4079                 .setContentText(details)
   4080                 .build();
   4081 
   4082         NotificationManager notificationManager = (NotificationManager)
   4083                 context.getSystemService(Context.NOTIFICATION_SERVICE);
   4084 
   4085         if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) {
   4086             // cancel previous post notification
   4087             notificationManager.cancel(notificationId);
   4088         } else {
   4089             // update restricted state notification
   4090             notificationManager.notify(notificationId, mNotification);
   4091         }
   4092     }
   4093 
   4094     private UiccCardApplication getUiccCardApplication() {
   4095         if (mPhone.isPhoneTypeGsm()) {
   4096             return mUiccController.getUiccCardApplication(mPhone.getPhoneId(),
   4097                     UiccController.APP_FAM_3GPP);
   4098         } else {
   4099             return mUiccController.getUiccCardApplication(mPhone.getPhoneId(),
   4100                     UiccController.APP_FAM_3GPP2);
   4101         }
   4102     }
   4103 
   4104     private void queueNextSignalStrengthPoll() {
   4105         if (mDontPollSignalStrength) {
   4106             // The radio is telling us about signal strength changes
   4107             // we don't have to ask it
   4108             return;
   4109         }
   4110 
   4111         Message msg;
   4112 
   4113         msg = obtainMessage();
   4114         msg.what = EVENT_POLL_SIGNAL_STRENGTH;
   4115 
   4116         long nextTime;
   4117 
   4118         // TODO Don't poll signal strength if screen is off
   4119         sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
   4120     }
   4121 
   4122     private void notifyCdmaSubscriptionInfoReady() {
   4123         if (mCdmaForSubscriptionInfoReadyRegistrants != null) {
   4124             if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()");
   4125             mCdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
   4126         }
   4127     }
   4128 
   4129     /**
   4130      * Registration point for transition into DataConnection attached.
   4131      * @param h handler to notify
   4132      * @param what what code of message when delivered
   4133      * @param obj placed in Message.obj
   4134      */
   4135     public void registerForDataConnectionAttached(Handler h, int what, Object obj) {
   4136         Registrant r = new Registrant(h, what, obj);
   4137         mAttachedRegistrants.add(r);
   4138 
   4139         if (getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
   4140             r.notifyRegistrant();
   4141         }
   4142     }
   4143     public void unregisterForDataConnectionAttached(Handler h) {
   4144         mAttachedRegistrants.remove(h);
   4145     }
   4146 
   4147     /**
   4148      * Registration point for transition into DataConnection detached.
   4149      * @param h handler to notify
   4150      * @param what what code of message when delivered
   4151      * @param obj placed in Message.obj
   4152      */
   4153     public void registerForDataConnectionDetached(Handler h, int what, Object obj) {
   4154         Registrant r = new Registrant(h, what, obj);
   4155         mDetachedRegistrants.add(r);
   4156 
   4157         if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
   4158             r.notifyRegistrant();
   4159         }
   4160     }
   4161     public void unregisterForDataConnectionDetached(Handler h) {
   4162         mDetachedRegistrants.remove(h);
   4163     }
   4164 
   4165     /**
   4166      * Registration for DataConnection RIL Data Radio Technology changing. The
   4167      * new radio technology will be returned AsyncResult#result as an Integer Object.
   4168      * The AsyncResult will be in the notification Message#obj.
   4169      *
   4170      * @param h handler to notify
   4171      * @param what what code of message when delivered
   4172      * @param obj placed in Message.obj
   4173      */
   4174     public void registerForDataRegStateOrRatChanged(Handler h, int what, Object obj) {
   4175         Registrant r = new Registrant(h, what, obj);
   4176         mDataRegStateOrRatChangedRegistrants.add(r);
   4177         notifyDataRegStateRilRadioTechnologyChanged();
   4178     }
   4179     public void unregisterForDataRegStateOrRatChanged(Handler h) {
   4180         mDataRegStateOrRatChangedRegistrants.remove(h);
   4181     }
   4182 
   4183     /**
   4184      * Registration point for transition into network attached.
   4185      * @param h handler to notify
   4186      * @param what what code of message when delivered
   4187      * @param obj in Message.obj
   4188      */
   4189     public void registerForNetworkAttached(Handler h, int what, Object obj) {
   4190         Registrant r = new Registrant(h, what, obj);
   4191 
   4192         mNetworkAttachedRegistrants.add(r);
   4193         if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
   4194             r.notifyRegistrant();
   4195         }
   4196     }
   4197     public void unregisterForNetworkAttached(Handler h) {
   4198         mNetworkAttachedRegistrants.remove(h);
   4199     }
   4200 
   4201     /**
   4202      * Registration point for transition into packet service restricted zone.
   4203      * @param h handler to notify
   4204      * @param what what code of message when delivered
   4205      * @param obj placed in Message.obj
   4206      */
   4207     public void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
   4208         Registrant r = new Registrant(h, what, obj);
   4209         mPsRestrictEnabledRegistrants.add(r);
   4210 
   4211         if (mRestrictedState.isPsRestricted()) {
   4212             r.notifyRegistrant();
   4213         }
   4214     }
   4215 
   4216     public void unregisterForPsRestrictedEnabled(Handler h) {
   4217         mPsRestrictEnabledRegistrants.remove(h);
   4218     }
   4219 
   4220     /**
   4221      * Registration point for transition out of packet service restricted zone.
   4222      * @param h handler to notify
   4223      * @param what what code of message when delivered
   4224      * @param obj placed in Message.obj
   4225      */
   4226     public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
   4227         Registrant r = new Registrant(h, what, obj);
   4228         mPsRestrictDisabledRegistrants.add(r);
   4229 
   4230         if (mRestrictedState.isPsRestricted()) {
   4231             r.notifyRegistrant();
   4232         }
   4233     }
   4234 
   4235     public void unregisterForPsRestrictedDisabled(Handler h) {
   4236         mPsRestrictDisabledRegistrants.remove(h);
   4237     }
   4238 
   4239     /**
   4240      * Clean up existing voice and data connection then turn off radio power.
   4241      *
   4242      * Hang up the existing voice calls to decrease call drop rate.
   4243      */
   4244     public void powerOffRadioSafely(DcTracker dcTracker) {
   4245         synchronized (this) {
   4246             if (!mPendingRadioPowerOffAfterDataOff) {
   4247                 if (mPhone.isPhoneTypeGsm() || mPhone.isPhoneTypeCdmaLte()) {
   4248                     int dds = SubscriptionManager.getDefaultDataSubscriptionId();
   4249                     // To minimize race conditions we call cleanUpAllConnections on
   4250                     // both if else paths instead of before this isDisconnected test.
   4251                     if (dcTracker.isDisconnected()
   4252                             && (dds == mPhone.getSubId()
   4253                             || (dds != mPhone.getSubId()
   4254                             && ProxyController.getInstance().isDataDisconnected(dds)))) {
   4255                         // To minimize race conditions we do this after isDisconnected
   4256                         dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
   4257                         if (DBG) log("Data disconnected, turn off radio right away.");
   4258                         hangupAndPowerOff();
   4259                     } else {
   4260                         // hang up all active voice calls first
   4261                         if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) {
   4262                             mPhone.mCT.mRingingCall.hangupIfAlive();
   4263                             mPhone.mCT.mBackgroundCall.hangupIfAlive();
   4264                             mPhone.mCT.mForegroundCall.hangupIfAlive();
   4265                         }
   4266                         dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
   4267                         if (dds != mPhone.getSubId()
   4268                                 && !ProxyController.getInstance().isDataDisconnected(dds)) {
   4269                             if (DBG) log("Data is active on DDS.  Wait for all data disconnect");
   4270                             // Data is not disconnected on DDS. Wait for the data disconnect complete
   4271                             // before sending the RADIO_POWER off.
   4272                             ProxyController.getInstance().registerForAllDataDisconnected(dds, this,
   4273                                     EVENT_ALL_DATA_DISCONNECTED, null);
   4274                             mPendingRadioPowerOffAfterDataOff = true;
   4275                         }
   4276                         Message msg = Message.obtain(this);
   4277                         msg.what = EVENT_SET_RADIO_POWER_OFF;
   4278                         msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
   4279                         if (sendMessageDelayed(msg, 30000)) {
   4280                             if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
   4281                             mPendingRadioPowerOffAfterDataOff = true;
   4282                         } else {
   4283                             log("Cannot send delayed Msg, turn off radio right away.");
   4284                             hangupAndPowerOff();
   4285                             mPendingRadioPowerOffAfterDataOff = false;
   4286                         }
   4287                     }
   4288                 } else {
   4289                     // In some network, deactivate PDP connection cause releasing of RRC connection,
   4290                     // which MM/IMSI detaching request needs. Without this detaching, network can
   4291                     // not release the network resources previously attached.
   4292                     // So we are avoiding data detaching on these networks.
   4293                     String[] networkNotClearData = mPhone.getContext().getResources()
   4294                             .getStringArray(com.android.internal.R.array.networks_not_clear_data);
   4295                     String currentNetwork = mSS.getOperatorNumeric();
   4296                     if ((networkNotClearData != null) && (currentNetwork != null)) {
   4297                         for (int i = 0; i < networkNotClearData.length; i++) {
   4298                             if (currentNetwork.equals(networkNotClearData[i])) {
   4299                                 // Don't clear data connection for this carrier
   4300                                 if (DBG)
   4301                                     log("Not disconnecting data for " + currentNetwork);
   4302                                 hangupAndPowerOff();
   4303                                 return;
   4304                             }
   4305                         }
   4306                     }
   4307                     // To minimize race conditions we call cleanUpAllConnections on
   4308                     // both if else paths instead of before this isDisconnected test.
   4309                     if (dcTracker.isDisconnected()) {
   4310                         // To minimize race conditions we do this after isDisconnected
   4311                         dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
   4312                         if (DBG) log("Data disconnected, turn off radio right away.");
   4313                         hangupAndPowerOff();
   4314                     } else {
   4315                         dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
   4316                         Message msg = Message.obtain(this);
   4317                         msg.what = EVENT_SET_RADIO_POWER_OFF;
   4318                         msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
   4319                         if (sendMessageDelayed(msg, 30000)) {
   4320                             if (DBG)
   4321                                 log("Wait upto 30s for data to disconnect, then turn off radio.");
   4322                             mPendingRadioPowerOffAfterDataOff = true;
   4323                         } else {
   4324                             log("Cannot send delayed Msg, turn off radio right away.");
   4325                             hangupAndPowerOff();
   4326                         }
   4327                     }
   4328                 }
   4329             }
   4330         }
   4331     }
   4332 
   4333     /**
   4334      * process the pending request to turn radio off after data is disconnected
   4335      *
   4336      * return true if there is pending request to process; false otherwise.
   4337      */
   4338     public boolean processPendingRadioPowerOffAfterDataOff() {
   4339         synchronized(this) {
   4340             if (mPendingRadioPowerOffAfterDataOff) {
   4341                 if (DBG) log("Process pending request to turn radio off.");
   4342                 mPendingRadioPowerOffAfterDataOffTag += 1;
   4343                 hangupAndPowerOff();
   4344                 mPendingRadioPowerOffAfterDataOff = false;
   4345                 return true;
   4346             }
   4347             return false;
   4348         }
   4349     }
   4350 
   4351     /**
   4352      * send signal-strength-changed notification if changed Called both for
   4353      * solicited and unsolicited signal strength updates
   4354      *
   4355      * @return true if the signal strength changed and a notification was sent.
   4356      */
   4357     protected boolean onSignalStrengthResult(AsyncResult ar) {
   4358         boolean isGsm = false;
   4359         //override isGsm for CDMA LTE
   4360         if (mPhone.isPhoneTypeGsm() ||
   4361                 (mPhone.isPhoneTypeCdmaLte() &&
   4362                         ServiceState.isLte(mSS.getRilDataRadioTechnology()))) {
   4363             isGsm = true;
   4364         }
   4365 
   4366         // This signal is used for both voice and data radio signal so parse
   4367         // all fields
   4368 
   4369         if ((ar.exception == null) && (ar.result != null)) {
   4370             mSignalStrength = (SignalStrength) ar.result;
   4371             mSignalStrength.validateInput();
   4372             mSignalStrength.setGsm(isGsm);
   4373         } else {
   4374             log("onSignalStrengthResult() Exception from RIL : " + ar.exception);
   4375             mSignalStrength = new SignalStrength(isGsm);
   4376         }
   4377 
   4378         boolean ssChanged = notifySignalStrength();
   4379 
   4380         return ssChanged;
   4381     }
   4382 
   4383     /**
   4384      * Hang up all voice call and turn off radio. Implemented by derived class.
   4385      */
   4386     protected void hangupAndPowerOff() {
   4387         // hang up all active voice calls
   4388         if (!mPhone.isPhoneTypeGsm() || mPhone.isInCall()) {
   4389             mPhone.mCT.mRingingCall.hangupIfAlive();
   4390             mPhone.mCT.mBackgroundCall.hangupIfAlive();
   4391             mPhone.mCT.mForegroundCall.hangupIfAlive();
   4392         }
   4393 
   4394         mCi.setRadioPower(false, null);
   4395 
   4396     }
   4397 
   4398     /** Cancel a pending (if any) pollState() operation */
   4399     protected void cancelPollState() {
   4400         // This will effectively cancel the rest of the poll requests.
   4401         mPollingContext = new int[1];
   4402     }
   4403 
   4404     /**
   4405      * Return true if time zone needs fixing.
   4406      *
   4407      * @param phone
   4408      * @param operatorNumeric
   4409      * @param prevOperatorNumeric
   4410      * @param needToFixTimeZone
   4411      * @return true if time zone needs to be fixed
   4412      */
   4413     protected boolean shouldFixTimeZoneNow(Phone phone, String operatorNumeric,
   4414             String prevOperatorNumeric, boolean needToFixTimeZone) {
   4415         // Return false if the mcc isn't valid as we don't know where we are.
   4416         // Return true if we have an IccCard and the mcc changed or we
   4417         // need to fix it because when the NITZ time came in we didn't
   4418         // know the country code.
   4419 
   4420         // If mcc is invalid then we'll return false
   4421         int mcc;
   4422         try {
   4423             mcc = Integer.parseInt(operatorNumeric.substring(0, 3));
   4424         } catch (Exception e) {
   4425             if (DBG) {
   4426                 log("shouldFixTimeZoneNow: no mcc, operatorNumeric=" + operatorNumeric +
   4427                         " retVal=false");
   4428             }
   4429             return false;
   4430         }
   4431 
   4432         // If prevMcc is invalid will make it different from mcc
   4433         // so we'll return true if the card exists.
   4434         int prevMcc;
   4435         try {
   4436             prevMcc = Integer.parseInt(prevOperatorNumeric.substring(0, 3));
   4437         } catch (Exception e) {
   4438             prevMcc = mcc + 1;
   4439         }
   4440 
   4441         // Determine if the Icc card exists
   4442         boolean iccCardExist = false;
   4443         if (mUiccApplcation != null) {
   4444             iccCardExist = mUiccApplcation.getState() != AppState.APPSTATE_UNKNOWN;
   4445         }
   4446 
   4447         // Determine retVal
   4448         boolean retVal = ((iccCardExist && (mcc != prevMcc)) || needToFixTimeZone);
   4449         if (DBG) {
   4450             long ctm = System.currentTimeMillis();
   4451             log("shouldFixTimeZoneNow: retVal=" + retVal +
   4452                     " iccCardExist=" + iccCardExist +
   4453                     " operatorNumeric=" + operatorNumeric + " mcc=" + mcc +
   4454                     " prevOperatorNumeric=" + prevOperatorNumeric + " prevMcc=" + prevMcc +
   4455                     " needToFixTimeZone=" + needToFixTimeZone +
   4456                     " ltod=" + TimeUtils.logTimeOfDay(ctm));
   4457         }
   4458         return retVal;
   4459     }
   4460 
   4461     public String getSystemProperty(String property, String defValue) {
   4462         return TelephonyManager.getTelephonyProperty(mPhone.getPhoneId(), property, defValue);
   4463     }
   4464 
   4465     /**
   4466      * @return all available cell information or null if none.
   4467      */
   4468     public List<CellInfo> getAllCellInfo() {
   4469         CellInfoResult result = new CellInfoResult();
   4470         if (VDBG) log("SST.getAllCellInfo(): E");
   4471         int ver = mCi.getRilVersion();
   4472         if (ver >= 8) {
   4473             if (isCallerOnDifferentThread()) {
   4474                 if ((SystemClock.elapsedRealtime() - mLastCellInfoListTime)
   4475                         > LAST_CELL_INFO_LIST_MAX_AGE_MS) {
   4476                     Message msg = obtainMessage(EVENT_GET_CELL_INFO_LIST, result);
   4477                     synchronized(result.lockObj) {
   4478                         result.list = null;
   4479                         mCi.getCellInfoList(msg);
   4480                         try {
   4481                             result.lockObj.wait(5000);
   4482                         } catch (InterruptedException e) {
   4483                             e.printStackTrace();
   4484                         }
   4485                     }
   4486                 } else {
   4487                     if (DBG) log("SST.getAllCellInfo(): return last, back to back calls");
   4488                     result.list = mLastCellInfoList;
   4489                 }
   4490             } else {
   4491                 if (DBG) log("SST.getAllCellInfo(): return last, same thread can't block");
   4492                 result.list = mLastCellInfoList;
   4493             }
   4494         } else {
   4495             if (DBG) log("SST.getAllCellInfo(): not implemented");
   4496             result.list = null;
   4497         }
   4498         synchronized(result.lockObj) {
   4499             if (result.list != null) {
   4500                 if (VDBG) log("SST.getAllCellInfo(): X size=" + result.list.size()
   4501                         + " list=" + result.list);
   4502                 return result.list;
   4503             } else {
   4504                 if (DBG) log("SST.getAllCellInfo(): X size=0 list=null");
   4505                 return null;
   4506             }
   4507         }
   4508     }
   4509 
   4510     /**
   4511      * @return signal strength
   4512      */
   4513     public SignalStrength getSignalStrength() {
   4514         return mSignalStrength;
   4515     }
   4516 
   4517     /**
   4518      * Registration point for subscription info ready
   4519      * @param h handler to notify
   4520      * @param what what code of message when delivered
   4521      * @param obj placed in Message.obj
   4522      */
   4523     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
   4524         Registrant r = new Registrant(h, what, obj);
   4525         mCdmaForSubscriptionInfoReadyRegistrants.add(r);
   4526 
   4527         if (isMinInfoReady()) {
   4528             r.notifyRegistrant();
   4529         }
   4530     }
   4531 
   4532     public void unregisterForSubscriptionInfoReady(Handler h) {
   4533         mCdmaForSubscriptionInfoReadyRegistrants.remove(h);
   4534     }
   4535 
   4536     /**
   4537      * Save current source of cdma subscription
   4538      * @param source - 1 for NV, 0 for RUIM
   4539      */
   4540     private void saveCdmaSubscriptionSource(int source) {
   4541         log("Storing cdma subscription source: " + source);
   4542         Settings.Global.putInt(mPhone.getContext().getContentResolver(),
   4543                 Settings.Global.CDMA_SUBSCRIPTION_MODE,
   4544                 source);
   4545         log("Read from settings: " + Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   4546                 Settings.Global.CDMA_SUBSCRIPTION_MODE, -1));
   4547     }
   4548 
   4549     private void getSubscriptionInfoAndStartPollingThreads() {
   4550         mCi.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
   4551 
   4552         // Get Registration Information
   4553         pollState();
   4554     }
   4555 
   4556     private void handleCdmaSubscriptionSource(int newSubscriptionSource) {
   4557         log("Subscription Source : " + newSubscriptionSource);
   4558         mIsSubscriptionFromRuim =
   4559                 (newSubscriptionSource == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM);
   4560         log("isFromRuim: " + mIsSubscriptionFromRuim);
   4561         saveCdmaSubscriptionSource(newSubscriptionSource);
   4562         if (!mIsSubscriptionFromRuim) {
   4563             // NV is ready when subscription source is NV
   4564             sendMessage(obtainMessage(EVENT_NV_READY));
   4565         }
   4566     }
   4567 
   4568     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   4569         pw.println("ServiceStateTracker:");
   4570         pw.println(" mSubId=" + mSubId);
   4571         pw.println(" mSS=" + mSS);
   4572         pw.println(" mNewSS=" + mNewSS);
   4573         pw.println(" mVoiceCapable=" + mVoiceCapable);
   4574         pw.println(" mRestrictedState=" + mRestrictedState);
   4575         pw.println(" mPollingContext=" + mPollingContext + " - " +
   4576                 (mPollingContext != null ? mPollingContext[0] : ""));
   4577         pw.println(" mDesiredPowerState=" + mDesiredPowerState);
   4578         pw.println(" mDontPollSignalStrength=" + mDontPollSignalStrength);
   4579         pw.println(" mSignalStrength=" + mSignalStrength);
   4580         pw.println(" mLastSignalStrength=" + mLastSignalStrength);
   4581         pw.println(" mRestrictedState=" + mRestrictedState);
   4582         pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff);
   4583         pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag);
   4584         pw.println(" mCellLoc=" + mCellLoc);
   4585         pw.println(" mNewCellLoc=" + mNewCellLoc);
   4586         pw.println(" mLastCellInfoListTime=" + mLastCellInfoListTime);
   4587         pw.println(" mPreferredNetworkType=" + mPreferredNetworkType);
   4588         pw.println(" mMaxDataCalls=" + mMaxDataCalls);
   4589         pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls);
   4590         pw.println(" mReasonDataDenied=" + mReasonDataDenied);
   4591         pw.println(" mNewReasonDataDenied=" + mNewReasonDataDenied);
   4592         pw.println(" mGsmRoaming=" + mGsmRoaming);
   4593         pw.println(" mDataRoaming=" + mDataRoaming);
   4594         pw.println(" mEmergencyOnly=" + mEmergencyOnly);
   4595         pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz);
   4596         pw.flush();
   4597         pw.println(" mZoneOffset=" + mZoneOffset);
   4598         pw.println(" mZoneDst=" + mZoneDst);
   4599         pw.println(" mZoneTime=" + mZoneTime);
   4600         pw.println(" mGotCountryCode=" + mGotCountryCode);
   4601         pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime);
   4602         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
   4603         pw.println(" mSavedTime=" + mSavedTime);
   4604         pw.println(" mSavedAtTime=" + mSavedAtTime);
   4605         pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
   4606         pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
   4607         pw.println(" mNotification=" + mNotification);
   4608         pw.println(" mWakeLock=" + mWakeLock);
   4609         pw.println(" mCurSpn=" + mCurSpn);
   4610         pw.println(" mCurDataSpn=" + mCurDataSpn);
   4611         pw.println(" mCurShowSpn=" + mCurShowSpn);
   4612         pw.println(" mCurPlmn=" + mCurPlmn);
   4613         pw.println(" mCurShowPlmn=" + mCurShowPlmn);
   4614         pw.flush();
   4615         pw.println(" mCurrentOtaspMode=" + mCurrentOtaspMode);
   4616         pw.println(" mRoamingIndicator=" + mRoamingIndicator);
   4617         pw.println(" mIsInPrl=" + mIsInPrl);
   4618         pw.println(" mDefaultRoamingIndicator=" + mDefaultRoamingIndicator);
   4619         pw.println(" mRegistrationState=" + mRegistrationState);
   4620         pw.println(" mMdn=" + mMdn);
   4621         pw.println(" mHomeSystemId=" + mHomeSystemId);
   4622         pw.println(" mHomeNetworkId=" + mHomeNetworkId);
   4623         pw.println(" mMin=" + mMin);
   4624         pw.println(" mPrlVersion=" + mPrlVersion);
   4625         pw.println(" mIsMinInfoReady=" + mIsMinInfoReady);
   4626         pw.println(" mIsEriTextLoaded=" + mIsEriTextLoaded);
   4627         pw.println(" mIsSubscriptionFromRuim=" + mIsSubscriptionFromRuim);
   4628         pw.println(" mCdmaSSM=" + mCdmaSSM);
   4629         pw.println(" mRegistrationDeniedReason=" + mRegistrationDeniedReason);
   4630         pw.println(" mCurrentCarrier=" + mCurrentCarrier);
   4631         pw.flush();
   4632         pw.println(" mImsRegistered=" + mImsRegistered);
   4633         pw.println(" mImsRegistrationOnOff=" + mImsRegistrationOnOff);
   4634         pw.println(" mAlarmSwitch=" + mAlarmSwitch);
   4635         pw.println(" mRadioDisabledByCarrier" + mRadioDisabledByCarrier);
   4636         pw.println(" mPowerOffDelayNeed=" + mPowerOffDelayNeed);
   4637         pw.println(" mDeviceShuttingDown=" + mDeviceShuttingDown);
   4638         pw.println(" mSpnUpdatePending=" + mSpnUpdatePending);
   4639 
   4640 
   4641     }
   4642 
   4643     public boolean isImsRegistered() {
   4644         return mImsRegistered;
   4645     }
   4646     /**
   4647      * Verifies the current thread is the same as the thread originally
   4648      * used in the initialization of this instance. Throws RuntimeException
   4649      * if not.
   4650      *
   4651      * @exception RuntimeException if the current thread is not
   4652      * the thread that originally obtained this Phone instance.
   4653      */
   4654     protected void checkCorrectThread() {
   4655         if (Thread.currentThread() != getLooper().getThread()) {
   4656             throw new RuntimeException(
   4657                     "ServiceStateTracker must be used from within one thread");
   4658         }
   4659     }
   4660 
   4661     protected boolean isCallerOnDifferentThread() {
   4662         boolean value = Thread.currentThread() != getLooper().getThread();
   4663         if (VDBG) log("isCallerOnDifferentThread: " + value);
   4664         return value;
   4665     }
   4666 
   4667     protected void updateCarrierMccMncConfiguration(String newOp, String oldOp, Context context) {
   4668         // if we have a change in operator, notify wifi (even to/from none)
   4669         if (((newOp == null) && (TextUtils.isEmpty(oldOp) == false)) ||
   4670                 ((newOp != null) && (newOp.equals(oldOp) == false))) {
   4671             log("update mccmnc=" + newOp + " fromServiceState=true");
   4672             MccTable.updateMccMncConfiguration(context, newOp, true);
   4673         }
   4674     }
   4675 
   4676     /**
   4677      * Check ISO country by MCC to see if phone is roaming in same registered country
   4678      */
   4679     protected boolean inSameCountry(String operatorNumeric) {
   4680         if (TextUtils.isEmpty(operatorNumeric) || (operatorNumeric.length() < 5)) {
   4681             // Not a valid network
   4682             return false;
   4683         }
   4684         final String homeNumeric = getHomeOperatorNumeric();
   4685         if (TextUtils.isEmpty(homeNumeric) || (homeNumeric.length() < 5)) {
   4686             // Not a valid SIM MCC
   4687             return false;
   4688         }
   4689         boolean inSameCountry = true;
   4690         final String networkMCC = operatorNumeric.substring(0, 3);
   4691         final String homeMCC = homeNumeric.substring(0, 3);
   4692         final String networkCountry = MccTable.countryCodeForMcc(Integer.parseInt(networkMCC));
   4693         final String homeCountry = MccTable.countryCodeForMcc(Integer.parseInt(homeMCC));
   4694         if (networkCountry.isEmpty() || homeCountry.isEmpty()) {
   4695             // Not a valid country
   4696             return false;
   4697         }
   4698         inSameCountry = homeCountry.equals(networkCountry);
   4699         if (inSameCountry) {
   4700             return inSameCountry;
   4701         }
   4702         // special same country cases
   4703         if ("us".equals(homeCountry) && "vi".equals(networkCountry)) {
   4704             inSameCountry = true;
   4705         } else if ("vi".equals(homeCountry) && "us".equals(networkCountry)) {
   4706             inSameCountry = true;
   4707         }
   4708         return inSameCountry;
   4709     }
   4710 
   4711     /**
   4712      * Set both voice and data roaming type,
   4713      * judging from the ISO country of SIM VS network.
   4714      */
   4715     protected void setRoamingType(ServiceState currentServiceState) {
   4716         final boolean isVoiceInService =
   4717                 (currentServiceState.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
   4718         if (isVoiceInService) {
   4719             if (currentServiceState.getVoiceRoaming()) {
   4720                 if (mPhone.isPhoneTypeGsm()) {
   4721                     // check roaming type by MCC
   4722                     if (inSameCountry(currentServiceState.getVoiceOperatorNumeric())) {
   4723                         currentServiceState.setVoiceRoamingType(
   4724                                 ServiceState.ROAMING_TYPE_DOMESTIC);
   4725                     } else {
   4726                         currentServiceState.setVoiceRoamingType(
   4727                                 ServiceState.ROAMING_TYPE_INTERNATIONAL);
   4728                     }
   4729                 } else {
   4730                     // some carrier defines international roaming by indicator
   4731                     int[] intRoamingIndicators = mPhone.getContext().getResources().getIntArray(
   4732                             com.android.internal.R.array.config_cdma_international_roaming_indicators);
   4733                     if ((intRoamingIndicators != null) && (intRoamingIndicators.length > 0)) {
   4734                         // It's domestic roaming at least now
   4735                         currentServiceState.setVoiceRoamingType(ServiceState.ROAMING_TYPE_DOMESTIC);
   4736                         int curRoamingIndicator = currentServiceState.getCdmaRoamingIndicator();
   4737                         for (int i = 0; i < intRoamingIndicators.length; i++) {
   4738                             if (curRoamingIndicator == intRoamingIndicators[i]) {
   4739                                 currentServiceState.setVoiceRoamingType(
   4740                                         ServiceState.ROAMING_TYPE_INTERNATIONAL);
   4741                                 break;
   4742                             }
   4743                         }
   4744                     } else {
   4745                         // check roaming type by MCC
   4746                         if (inSameCountry(currentServiceState.getVoiceOperatorNumeric())) {
   4747                             currentServiceState.setVoiceRoamingType(
   4748                                     ServiceState.ROAMING_TYPE_DOMESTIC);
   4749                         } else {
   4750                             currentServiceState.setVoiceRoamingType(
   4751                                     ServiceState.ROAMING_TYPE_INTERNATIONAL);
   4752                         }
   4753                     }
   4754                 }
   4755             } else {
   4756                 currentServiceState.setVoiceRoamingType(ServiceState.ROAMING_TYPE_NOT_ROAMING);
   4757             }
   4758         }
   4759         final boolean isDataInService =
   4760                 (currentServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE);
   4761         final int dataRegType = currentServiceState.getRilDataRadioTechnology();
   4762         if (isDataInService) {
   4763             if (!currentServiceState.getDataRoaming()) {
   4764                 currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_NOT_ROAMING);
   4765             } else {
   4766                 if (mPhone.isPhoneTypeGsm()) {
   4767                     if (ServiceState.isGsm(dataRegType)) {
   4768                         if (isVoiceInService) {
   4769                             // GSM data should have the same state as voice
   4770                             currentServiceState.setDataRoamingType(currentServiceState
   4771                                     .getVoiceRoamingType());
   4772                         } else {
   4773                             // we can not decide GSM data roaming type without voice
   4774                             currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_UNKNOWN);
   4775                         }
   4776                     } else {
   4777                         // we can not decide 3gpp2 roaming state here
   4778                         currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_UNKNOWN);
   4779                     }
   4780                 } else {
   4781                     if (ServiceState.isCdma(dataRegType)) {
   4782                         if (isVoiceInService) {
   4783                             // CDMA data should have the same state as voice
   4784                             currentServiceState.setDataRoamingType(currentServiceState
   4785                                     .getVoiceRoamingType());
   4786                         } else {
   4787                             // we can not decide CDMA data roaming type without voice
   4788                             // set it as same as last time
   4789                             currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_UNKNOWN);
   4790                         }
   4791                     } else {
   4792                         // take it as 3GPP roaming
   4793                         if (inSameCountry(currentServiceState.getDataOperatorNumeric())) {
   4794                             currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_DOMESTIC);
   4795                         } else {
   4796                             currentServiceState.setDataRoamingType(
   4797                                     ServiceState.ROAMING_TYPE_INTERNATIONAL);
   4798                         }
   4799                     }
   4800                 }
   4801             }
   4802         }
   4803     }
   4804 
   4805     private void setSignalStrengthDefaultValues() {
   4806         mSignalStrength = new SignalStrength(true);
   4807     }
   4808 
   4809     protected String getHomeOperatorNumeric() {
   4810         String numeric = ((TelephonyManager) mPhone.getContext().
   4811                 getSystemService(Context.TELEPHONY_SERVICE)).
   4812                 getSimOperatorNumericForPhone(mPhone.getPhoneId());
   4813         if (!mPhone.isPhoneTypeGsm() && TextUtils.isEmpty(numeric)) {
   4814             numeric = SystemProperties.get(GsmCdmaPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC, "");
   4815         }
   4816         return numeric;
   4817     }
   4818 
   4819     protected int getPhoneId() {
   4820         return mPhone.getPhoneId();
   4821     }
   4822 
   4823     /* Reset Service state when IWLAN is enabled as polling in airplane mode
   4824      * causes state to go to OUT_OF_SERVICE state instead of STATE_OFF
   4825      */
   4826     protected void resetServiceStateInIwlanMode() {
   4827         if (mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
   4828             boolean resetIwlanRatVal = false;
   4829             log("set service state as POWER_OFF");
   4830             if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
   4831                         == mNewSS.getRilDataRadioTechnology()) {
   4832                 log("pollStateDone: mNewSS = " + mNewSS);
   4833                 log("pollStateDone: reset iwlan RAT value");
   4834                 resetIwlanRatVal = true;
   4835             }
   4836             // operator info should be kept in SS
   4837             String operator = mNewSS.getOperatorAlphaLong();
   4838             mNewSS.setStateOff();
   4839             if (resetIwlanRatVal) {
   4840                 mNewSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN);
   4841                 mNewSS.setDataRegState(ServiceState.STATE_IN_SERVICE);
   4842                 mNewSS.setOperatorAlphaLong(operator);
   4843                 log("pollStateDone: mNewSS = " + mNewSS);
   4844             }
   4845         }
   4846     }
   4847 
   4848     /**
   4849      * Check if device is non-roaming and always on home network.
   4850      *
   4851      * @param b carrier config bundle obtained from CarrierConfigManager
   4852      * @return true if network is always on home network, false otherwise
   4853      * @see CarrierConfigManager
   4854      */
   4855     protected final boolean alwaysOnHomeNetwork(BaseBundle b) {
   4856         return b.getBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL);
   4857     }
   4858 
   4859     /**
   4860      * Check if the network identifier has membership in the set of
   4861      * network identifiers stored in the carrier config bundle.
   4862      *
   4863      * @param b carrier config bundle obtained from CarrierConfigManager
   4864      * @param network The network identifier to check network existence in bundle
   4865      * @param key The key to index into the bundle presenting a string array of
   4866      *            networks to check membership
   4867      * @return true if network has membership in bundle networks, false otherwise
   4868      * @see CarrierConfigManager
   4869      */
   4870     private boolean isInNetwork(BaseBundle b, String network, String key) {
   4871         String[] networks = b.getStringArray(key);
   4872 
   4873         if (networks != null && Arrays.asList(networks).contains(network)) {
   4874             return true;
   4875         }
   4876         return false;
   4877     }
   4878 
   4879     protected final boolean isRoamingInGsmNetwork(BaseBundle b, String network) {
   4880         return isInNetwork(b, network, CarrierConfigManager.KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY);
   4881     }
   4882 
   4883     protected final boolean isNonRoamingInGsmNetwork(BaseBundle b, String network) {
   4884         return isInNetwork(b, network, CarrierConfigManager.KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY);
   4885     }
   4886 
   4887     protected final boolean isRoamingInCdmaNetwork(BaseBundle b, String network) {
   4888         return isInNetwork(b, network, CarrierConfigManager.KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY);
   4889     }
   4890 
   4891     protected final boolean isNonRoamingInCdmaNetwork(BaseBundle b, String network) {
   4892         return isInNetwork(b, network, CarrierConfigManager.KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY);
   4893     }
   4894 
   4895     /** Check if the device is shutting down. */
   4896     public boolean isDeviceShuttingDown() {
   4897         return mDeviceShuttingDown;
   4898     }
   4899 }
   4900