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