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