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