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