Consider Service State OFF same as OUT OF SERVICE for combined regState
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / ServiceStateTracker.java
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 (DBG) 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 (DBG) 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 (DBG) 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 (DBG) {
3445                                 log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther);
3446                             }
3447                         }
3448                     }
3449                 }
3450                 if (DBG) {
3451                     log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther);
3452                 }
3453                 return cellLocOther;
3454             } else {
3455                 if (DBG) {
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=" + mCellLoc);
4558         pw.println(" mNewCellLoc=" + 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 }