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