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