]> nv-tegra.nvidia Code Review - android/platform/frameworks/opt/telephony.git/blob - src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
ca1e08d4becac786816f6ffbc27ee289f8f2787a
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / gsm / GsmServiceStateTracker.java
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.gsm;
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.res.Resources;
29 import android.database.ContentObserver;
30 import android.os.AsyncResult;
31 import android.os.Build;
32 import android.os.Handler;
33 import android.os.Message;
34 import android.os.PowerManager;
35 import android.os.SystemClock;
36 import android.os.SystemProperties;
37 import android.os.UserHandle;
38 import android.provider.Settings;
39 import android.provider.Settings.SettingNotFoundException;
40 import android.telephony.CellIdentityGsm;
41 import android.telephony.CellIdentityLte;
42 import android.telephony.CellIdentityWcdma;
43 import android.telephony.CellInfo;
44 import android.telephony.CellInfoGsm;
45 import android.telephony.CellInfoLte;
46 import android.telephony.CellInfoWcdma;
47 import android.telephony.CellLocation;
48 import android.telephony.Rlog;
49 import android.telephony.ServiceState;
50 import android.telephony.SignalStrength;
51 import android.telephony.gsm.GsmCellLocation;
52 import android.text.TextUtils;
53 import android.util.EventLog;
54 import android.util.TimeUtils;
55
56 import com.android.internal.telephony.CommandException;
57 import com.android.internal.telephony.CommandsInterface;
58 import com.android.internal.telephony.EventLogTags;
59 import com.android.internal.telephony.MccTable;
60 import com.android.internal.telephony.Phone;
61 import com.android.internal.telephony.RILConstants;
62 import com.android.internal.telephony.RestrictedState;
63 import com.android.internal.telephony.ServiceStateTracker;
64 import com.android.internal.telephony.TelephonyIntents;
65 import com.android.internal.telephony.TelephonyProperties;
66 import com.android.internal.telephony.dataconnection.DcTrackerBase;
67 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
68 import com.android.internal.telephony.uicc.IccRecords;
69 import com.android.internal.telephony.uicc.SIMRecords;
70 import com.android.internal.telephony.uicc.UiccCardApplication;
71 import com.android.internal.telephony.uicc.UiccController;
72
73 import java.io.FileDescriptor;
74 import java.io.PrintWriter;
75 import java.util.ArrayList;
76 import java.util.Arrays;
77 import java.util.Calendar;
78 import java.util.Date;
79 import java.util.List;
80 import java.util.TimeZone;
81
82 /**
83  * {@hide}
84  */
85 final class GsmServiceStateTracker extends ServiceStateTracker {
86     private static final String LOG_TAG = "GsmSST";
87     private static final boolean VDBG = false;
88
89     GSMPhone mPhone;
90     GsmCellLocation mCellLoc;
91     GsmCellLocation mNewCellLoc;
92     int mPreferredNetworkType;
93
94     private int mMaxDataCalls = 1;
95     private int mNewMaxDataCalls = 1;
96     private int mReasonDataDenied = -1;
97     private int mNewReasonDataDenied = -1;
98
99     /**
100      * GSM roaming status solely based on TS 27.007 7.2 CREG. Only used by
101      * handlePollStateResult to store CREG roaming result.
102      */
103     private boolean mGsmRoaming = false;
104
105     /**
106      * Data roaming status solely based on TS 27.007 10.1.19 CGREG. Only used by
107      * handlePollStateResult to store CGREG roaming result.
108      */
109     private boolean mDataRoaming = false;
110
111     /**
112      * Mark when service state is in emergency call only mode
113      */
114     private boolean mEmergencyOnly = false;
115
116     /**
117      * Sometimes we get the NITZ time before we know what country we
118      * are in. Keep the time zone information from the NITZ string so
119      * we can fix the time zone once know the country.
120      */
121     private boolean mNeedFixZoneAfterNitz = false;
122     private int mZoneOffset;
123     private boolean mZoneDst;
124     private long mZoneTime;
125     private boolean mGotCountryCode = false;
126     private ContentResolver mCr;
127
128     /** Boolean is true is setTimeFromNITZString was called */
129     private boolean mNitzUpdatedTime = false;
130
131     String mSavedTimeZone;
132     long mSavedTime;
133     long mSavedAtTime;
134
135     /** Started the recheck process after finding gprs should registered but not. */
136     private boolean mStartedGprsRegCheck = false;
137
138     /** Already sent the event-log for no gprs register. */
139     private boolean mReportedGprsNoReg = false;
140
141     /**
142      * The Notification object given to the NotificationManager.
143      */
144     private Notification mNotification;
145
146     /** Wake lock used while setting time of day. */
147     private PowerManager.WakeLock mWakeLock;
148     private static final String WAKELOCK_TAG = "ServiceStateTracker";
149
150     /** Keep track of SPN display rules, so we only broadcast intent if something changes. */
151     private String mCurSpn = null;
152     private String mCurPlmn = null;
153     private boolean mCurShowPlmn = false;
154     private boolean mCurShowSpn = false;
155
156     /** Notification type. */
157     static final int PS_ENABLED = 1001;            // Access Control blocks data service
158     static final int PS_DISABLED = 1002;           // Access Control enables data service
159     static final int CS_ENABLED = 1003;            // Access Control blocks all voice/sms service
160     static final int CS_DISABLED = 1004;           // Access Control enables all voice/sms service
161     static final int CS_NORMAL_ENABLED = 1005;     // Access Control blocks normal voice/sms service
162     static final int CS_EMERGENCY_ENABLED = 1006;  // Access Control blocks emergency call service
163
164     /** Notification id. */
165     static final int PS_NOTIFICATION = 888;  // Id to update and cancel PS restricted
166     static final int CS_NOTIFICATION = 999;  // Id to update and cancel CS restricted
167
168     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
169         @Override
170         public void onReceive(Context context, Intent intent) {
171             if (!mPhone.mIsTheCurrentActivePhone) {
172                 Rlog.e(LOG_TAG, "Received Intent " + intent +
173                         " while being destroyed. Ignoring.");
174                 return;
175             }
176
177             if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
178                 // update emergency string whenever locale changed
179                 updateSpnDisplay();
180             }
181         }
182     };
183
184     private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
185         @Override
186         public void onChange(boolean selfChange) {
187             Rlog.i("GsmServiceStateTracker", "Auto time state changed");
188             revertToNitzTime();
189         }
190     };
191
192     private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
193         @Override
194         public void onChange(boolean selfChange) {
195             Rlog.i("GsmServiceStateTracker", "Auto time zone state changed");
196             revertToNitzTimeZone();
197         }
198     };
199
200     public GsmServiceStateTracker(GSMPhone phone) {
201         super(phone, phone.mCi, new CellInfoGsm());
202
203         mPhone = phone;
204         mCellLoc = new GsmCellLocation();
205         mNewCellLoc = new GsmCellLocation();
206
207         PowerManager powerManager =
208                 (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
209         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
210
211         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
212         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
213
214         mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
215         mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
216         mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
217
218         // system setting property AIRPLANE_MODE_ON is set in Settings.
219         int airplaneMode = Settings.Global.getInt(
220                 phone.getContext().getContentResolver(),
221                 Settings.Global.AIRPLANE_MODE_ON, 0);
222         mDesiredPowerState = ! (airplaneMode > 0);
223
224         mCr = phone.getContext().getContentResolver();
225         mCr.registerContentObserver(
226                 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
227                 mAutoTimeObserver);
228         mCr.registerContentObserver(
229                 Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
230                 mAutoTimeZoneObserver);
231
232         setSignalStrengthDefaultValues();
233
234         // Monitor locale change
235         IntentFilter filter = new IntentFilter();
236         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
237         phone.getContext().registerReceiver(mIntentReceiver, filter);
238
239         // Gsm doesn't support OTASP so its not needed
240         phone.notifyOtaspChanged(OTASP_NOT_NEEDED);
241     }
242
243     @Override
244     public void dispose() {
245         checkCorrectThread();
246         log("ServiceStateTracker dispose");
247
248         // Unregister for all events.
249         mCi.unregisterForAvailable(this);
250         mCi.unregisterForRadioStateChanged(this);
251         mCi.unregisterForVoiceNetworkStateChanged(this);
252         if (mUiccApplcation != null) {mUiccApplcation.unregisterForReady(this);}
253         if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
254         mCi.unSetOnRestrictedStateChanged(this);
255         mCi.unSetOnNITZTime(this);
256         mCr.unregisterContentObserver(mAutoTimeObserver);
257         mCr.unregisterContentObserver(mAutoTimeZoneObserver);
258         mPhone.getContext().unregisterReceiver(mIntentReceiver);
259         super.dispose();
260     }
261
262     @Override
263     protected void finalize() {
264         if(DBG) log("finalize");
265     }
266
267     @Override
268     protected Phone getPhone() {
269         return mPhone;
270     }
271
272     @Override
273     public void handleMessage (Message msg) {
274         AsyncResult ar;
275         int[] ints;
276         String[] strings;
277         Message message;
278
279         if (!mPhone.mIsTheCurrentActivePhone) {
280             Rlog.e(LOG_TAG, "Received message " + msg +
281                     "[" + msg.what + "] while being destroyed. Ignoring.");
282             return;
283         }
284         switch (msg.what) {
285             case EVENT_RADIO_AVAILABLE:
286                 //this is unnecessary
287                 //setPowerStateToDesired();
288                 break;
289
290             case EVENT_SIM_READY:
291                 // Set the network type, in case the radio does not restore it.
292                 mCi.setCurrentPreferredNetworkType();
293
294                 boolean skipRestoringSelection = mPhone.getContext().getResources().getBoolean(
295                         com.android.internal.R.bool.skip_restoring_network_selection);
296
297                 if (!skipRestoringSelection) {
298                     // restore the previous network selection.
299                     mPhone.restoreSavedNetworkSelection(null);
300                 }
301                 pollState();
302                 // Signal strength polling stops when radio is off
303                 queueNextSignalStrengthPoll();
304                 break;
305
306             case EVENT_RADIO_STATE_CHANGED:
307                 // This will do nothing in the radio not
308                 // available case
309                 setPowerStateToDesired();
310                 pollState();
311                 break;
312
313             case EVENT_NETWORK_STATE_CHANGED:
314                 pollState();
315                 break;
316
317             case EVENT_GET_SIGNAL_STRENGTH:
318                 // This callback is called when signal strength is polled
319                 // all by itself
320
321                 if (!(mCi.getRadioState().isOn())) {
322                     // Polling will continue when radio turns back on
323                     return;
324                 }
325                 ar = (AsyncResult) msg.obj;
326                 onSignalStrengthResult(ar, true);
327                 queueNextSignalStrengthPoll();
328
329                 break;
330
331             case EVENT_GET_LOC_DONE:
332                 ar = (AsyncResult) msg.obj;
333
334                 if (ar.exception == null) {
335                     String states[] = (String[])ar.result;
336                     int lac = -1;
337                     int cid = -1;
338                     if (states.length >= 3) {
339                         try {
340                             if (states[1] != null && states[1].length() > 0) {
341                                 lac = Integer.parseInt(states[1], 16);
342                             }
343                             if (states[2] != null && states[2].length() > 0) {
344                                 cid = Integer.parseInt(states[2], 16);
345                             }
346                         } catch (NumberFormatException ex) {
347                             Rlog.w(LOG_TAG, "error parsing location: " + ex);
348                         }
349                     }
350                     mCellLoc.setLacAndCid(lac, cid);
351                     mPhone.notifyLocationChanged();
352                 }
353
354                 // Release any temporary cell lock, which could have been
355                 // acquired to allow a single-shot location update.
356                 disableSingleLocationUpdate();
357                 break;
358
359             case EVENT_POLL_STATE_REGISTRATION:
360             case EVENT_POLL_STATE_GPRS:
361             case EVENT_POLL_STATE_OPERATOR:
362             case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
363                 ar = (AsyncResult) msg.obj;
364
365                 handlePollStateResult(msg.what, ar);
366                 break;
367
368             case EVENT_POLL_SIGNAL_STRENGTH:
369                 // Just poll signal strength...not part of pollState()
370
371                 mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
372                 break;
373
374             case EVENT_NITZ_TIME:
375                 ar = (AsyncResult) msg.obj;
376
377                 String nitzString = (String)((Object[])ar.result)[0];
378                 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
379
380                 setTimeFromNITZString(nitzString, nitzReceiveTime);
381                 break;
382
383             case EVENT_SIGNAL_STRENGTH_UPDATE:
384                 // This is a notification from
385                 // CommandsInterface.setOnSignalStrengthUpdate
386
387                 ar = (AsyncResult) msg.obj;
388
389                 // The radio is telling us about signal strength changes
390                 // we don't have to ask it
391                 mDontPollSignalStrength = true;
392
393                 onSignalStrengthResult(ar, true);
394                 break;
395
396             case EVENT_SIM_RECORDS_LOADED:
397                 log("EVENT_SIM_RECORDS_LOADED: what=" + msg.what);
398
399                 updatePhoneObject();
400                 updateSpnDisplay();
401                 break;
402
403             case EVENT_LOCATION_UPDATES_ENABLED:
404                 ar = (AsyncResult) msg.obj;
405
406                 if (ar.exception == null) {
407                     mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null));
408                 }
409                 break;
410
411             case EVENT_SET_PREFERRED_NETWORK_TYPE:
412                 ar = (AsyncResult) msg.obj;
413                 // Don't care the result, only use for dereg network (COPS=2)
414                 message = obtainMessage(EVENT_RESET_PREFERRED_NETWORK_TYPE, ar.userObj);
415                 mCi.setPreferredNetworkType(mPreferredNetworkType, message);
416                 break;
417
418             case EVENT_RESET_PREFERRED_NETWORK_TYPE:
419                 ar = (AsyncResult) msg.obj;
420                 if (ar.userObj != null) {
421                     AsyncResult.forMessage(((Message) ar.userObj)).exception
422                             = ar.exception;
423                     ((Message) ar.userObj).sendToTarget();
424                 }
425                 break;
426
427             case EVENT_GET_PREFERRED_NETWORK_TYPE:
428                 ar = (AsyncResult) msg.obj;
429
430                 if (ar.exception == null) {
431                     mPreferredNetworkType = ((int[])ar.result)[0];
432                 } else {
433                     mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
434                 }
435
436                 message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj);
437                 int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
438
439                 mCi.setPreferredNetworkType(toggledNetworkType, message);
440                 break;
441
442             case EVENT_CHECK_REPORT_GPRS:
443                 if (mSS != null && !isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
444
445                     // Can't register data service while voice service is ok
446                     // i.e. CREG is ok while CGREG is not
447                     // possible a network or baseband side error
448                     GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
449                     EventLog.writeEvent(EventLogTags.DATA_NETWORK_REGISTRATION_FAIL,
450                             mSS.getOperatorNumeric(), loc != null ? loc.getCid() : -1);
451                     mReportedGprsNoReg = true;
452                 }
453                 mStartedGprsRegCheck = false;
454                 break;
455
456             case EVENT_RESTRICTED_STATE_CHANGED:
457                 // This is a notification from
458                 // CommandsInterface.setOnRestrictedStateChanged
459
460                 if (DBG) log("EVENT_RESTRICTED_STATE_CHANGED");
461
462                 ar = (AsyncResult) msg.obj;
463
464                 onRestrictedStateChanged(ar);
465                 break;
466
467             default:
468                 super.handleMessage(msg);
469             break;
470         }
471     }
472
473     @Override
474     protected void setPowerStateToDesired() {
475         // If we want it on and it's off, turn it on
476         if (mDesiredPowerState
477             && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
478             mCi.setRadioPower(true, null);
479         } else if (!mDesiredPowerState && mCi.getRadioState().isOn()) {
480             // If it's on and available and we want it off gracefully
481             DcTrackerBase dcTracker = mPhone.mDcTracker;
482             powerOffRadioSafely(dcTracker);
483         } // Otherwise, we're in the desired state
484     }
485
486     @Override
487     protected void hangupAndPowerOff() {
488         // hang up all active voice calls
489         if (mPhone.isInCall()) {
490             mPhone.mCT.mRingingCall.hangupIfAlive();
491             mPhone.mCT.mBackgroundCall.hangupIfAlive();
492             mPhone.mCT.mForegroundCall.hangupIfAlive();
493         }
494
495         mCi.setRadioPower(false, null);
496     }
497
498     @Override
499     protected void updateSpnDisplay() {
500         // The values of plmn/showPlmn change in different scenarios.
501         // 1) No service but emergency call allowed -> expected
502         //    to show "Emergency call only"
503         //    EXTRA_SHOW_PLMN = true
504         //    EXTRA_PLMN = "Emergency call only"
505
506         // 2) No service at all --> expected to show "No service"
507         //    EXTRA_SHOW_PLMN = true
508         //    EXTRA_PLMN = "No service"
509
510         // 3) Normal operation in either home or roaming service
511         //    EXTRA_SHOW_PLMN = depending on IccRecords rule
512         //    EXTRA_PLMN = plmn
513
514         // 4) No service due to power off, aka airplane mode
515         //    EXTRA_SHOW_PLMN = false
516         //    EXTRA_PLMN = null
517
518         IccRecords iccRecords = mIccRecords;
519         String plmn = null;
520         boolean showPlmn = false;
521         int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0;
522         if (mSS.getVoiceRegState() == ServiceState.STATE_OUT_OF_SERVICE
523                 || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY) {
524             showPlmn = true;
525             if (mEmergencyOnly) {
526                 // No service but emergency call allowed
527                 plmn = Resources.getSystem().
528                         getText(com.android.internal.R.string.emergency_calls_only).toString();
529             } else {
530                 // No service at all
531                 plmn = Resources.getSystem().
532                         getText(com.android.internal.R.string.lockscreen_carrier_default).toString();
533             }
534             if (DBG) log("updateSpnDisplay: radio is on but out " +
535                     "of service, set plmn='" + plmn + "'");
536         } else if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
537             // In either home or roaming service
538             plmn = mSS.getOperatorAlphaLong();
539             showPlmn = !TextUtils.isEmpty(plmn) &&
540                     ((rule & SIMRecords.SPN_RULE_SHOW_PLMN)
541                             == SIMRecords.SPN_RULE_SHOW_PLMN);
542         } else {
543             // Power off state, such as airplane mode
544             if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn="
545                     + showPlmn + " plmn=" + plmn);
546         }
547
548         // The value of spn/showSpn are same in different scenarios.
549         //    EXTRA_SHOW_SPN = depending on IccRecords rule
550         //    EXTRA_SPN = spn
551         String spn = (iccRecords != null) ? iccRecords.getServiceProviderName() : "";
552         boolean showSpn = !TextUtils.isEmpty(spn)
553                 && ((rule & SIMRecords.SPN_RULE_SHOW_SPN)
554                         == SIMRecords.SPN_RULE_SHOW_SPN);
555
556         // Update SPN_STRINGS_UPDATED_ACTION IFF any value changes
557         if (showPlmn != mCurShowPlmn
558                 || showSpn != mCurShowSpn
559                 || !TextUtils.equals(spn, mCurSpn)
560                 || !TextUtils.equals(plmn, mCurPlmn)) {
561             if (DBG) {
562                 log(String.format("updateSpnDisplay: changed" +
563                         " sending intent rule=" + rule +
564                         " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s'",
565                         showPlmn, plmn, showSpn, spn));
566             }
567             Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
568             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
569             intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn);
570             intent.putExtra(TelephonyIntents.EXTRA_SPN, spn);
571             intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
572             intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
573             mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
574         }
575
576         mCurShowSpn = showSpn;
577         mCurShowPlmn = showPlmn;
578         mCurSpn = spn;
579         mCurPlmn = plmn;
580     }
581
582     /**
583      * Handle the result of one of the pollState()-related requests
584      */
585     @Override
586     protected void handlePollStateResult (int what, AsyncResult ar) {
587         int ints[];
588         String states[];
589
590         // Ignore stale requests from last poll
591         if (ar.userObj != mPollingContext) return;
592
593         if (ar.exception != null) {
594             CommandException.Error err=null;
595
596             if (ar.exception instanceof CommandException) {
597                 err = ((CommandException)(ar.exception)).getCommandError();
598             }
599
600             if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
601                 // Radio has crashed or turned off
602                 cancelPollState();
603                 return;
604             }
605
606             if (!mCi.getRadioState().isOn()) {
607                 // Radio has crashed or turned off
608                 cancelPollState();
609                 return;
610             }
611
612             if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
613                 loge("RIL implementation has returned an error where it must succeed" +
614                         ar.exception);
615             }
616         } else try {
617             switch (what) {
618                 case EVENT_POLL_STATE_REGISTRATION: {
619                     states = (String[])ar.result;
620                     int lac = -1;
621                     int cid = -1;
622                     int type = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
623                     int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
624                     int reasonRegStateDenied = -1;
625                     int psc = -1;
626                     if (states.length > 0) {
627                         try {
628                             regState = Integer.parseInt(states[0]);
629                             if (states.length >= 3) {
630                                 if (states[1] != null && states[1].length() > 0) {
631                                     lac = Integer.parseInt(states[1], 16);
632                                 }
633                                 if (states[2] != null && states[2].length() > 0) {
634                                     cid = Integer.parseInt(states[2], 16);
635                                 }
636
637                                 // states[3] (if present) is the current radio technology
638                                 if (states.length >= 4 && states[3] != null) {
639                                     type = Integer.parseInt(states[3]);
640                                 }
641                             }
642                             if (states.length > 14) {
643                                 if (states[14] != null && states[14].length() > 0) {
644                                     psc = Integer.parseInt(states[14], 16);
645                                 }
646                             }
647                         } catch (NumberFormatException ex) {
648                             loge("error parsing RegistrationState: " + ex);
649                         }
650                     }
651
652                     mGsmRoaming = regCodeIsRoaming(regState);
653                     mNewSS.setState(regCodeToServiceState(regState));
654                     mNewSS.setRilVoiceRadioTechnology(type);
655
656                     boolean isVoiceCapable = mPhoneBase.getContext().getResources()
657                             .getBoolean(com.android.internal.R.bool.config_voice_capable);
658                     if ((regState == ServiceState.RIL_REG_STATE_DENIED_EMERGENCY_CALL_ENABLED
659                          || regState == ServiceState.RIL_REG_STATE_NOT_REG_EMERGENCY_CALL_ENABLED
660                          || regState == ServiceState.RIL_REG_STATE_SEARCHING_EMERGENCY_CALL_ENABLED
661                          || regState == ServiceState.RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED)
662                          && isVoiceCapable) {
663                         mEmergencyOnly = true;
664                     } else {
665                         mEmergencyOnly = false;
666                     }
667
668                     // LAC and CID are -1 if not avail
669                     mNewCellLoc.setLacAndCid(lac, cid);
670                     mNewCellLoc.setPsc(psc);
671                     break;
672                 }
673
674                 case EVENT_POLL_STATE_GPRS: {
675                     states = (String[])ar.result;
676
677                     int type = 0;
678                     int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
679                     mNewReasonDataDenied = -1;
680                     mNewMaxDataCalls = 1;
681                     if (states.length > 0) {
682                         try {
683                             regState = Integer.parseInt(states[0]);
684
685                             // states[3] (if present) is the current radio technology
686                             if (states.length >= 4 && states[3] != null) {
687                                 type = Integer.parseInt(states[3]);
688                             }
689                             if ((states.length >= 5 ) &&
690                                     (regState == ServiceState.RIL_REG_STATE_DENIED)) {
691                                 mNewReasonDataDenied = Integer.parseInt(states[4]);
692                             }
693                             if (states.length >= 6) {
694                                 mNewMaxDataCalls = Integer.parseInt(states[5]);
695                             }
696                         } catch (NumberFormatException ex) {
697                             loge("error parsing GprsRegistrationState: " + ex);
698                         }
699                     }
700                     int dataRegState = regCodeToServiceState(regState);
701                     mNewSS.setDataRegState(dataRegState);
702                     mDataRoaming = regCodeIsRoaming(regState);
703                     mNewSS.setRilDataRadioTechnology(type);
704                     if (DBG) {
705                         log("handlPollStateResultMessage: GsmSST setDataRegState=" + dataRegState
706                                 + " regState=" + regState
707                                 + " dataRadioTechnology=" + type);
708                     }
709                     break;
710                 }
711
712                 case EVENT_POLL_STATE_OPERATOR: {
713                     String opNames[] = (String[])ar.result;
714
715                     if (opNames != null && opNames.length >= 3) {
716                          mNewSS.setOperatorName (opNames[0], opNames[1], opNames[2]);
717                     }
718                     break;
719                 }
720
721                 case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: {
722                     ints = (int[])ar.result;
723                     mNewSS.setIsManualSelection(ints[0] == 1);
724                     break;
725                 }
726             }
727
728         } catch (RuntimeException ex) {
729             loge("Exception while polling service state. Probably malformed RIL response." + ex);
730         }
731
732         mPollingContext[0]--;
733
734         if (mPollingContext[0] == 0) {
735             /**
736              * Since the roaming state of gsm service (from +CREG) and
737              * data service (from +CGREG) could be different, the new SS
738              * is set to roaming when either is true.
739              *
740              * There are exceptions for the above rule.
741              * The new SS is not set as roaming while gsm service reports
742              * roaming but indeed it is same operator.
743              * And the operator is considered non roaming.
744              *
745              * The test for the operators is to handle special roaming
746              * agreements and MVNO's.
747              */
748             boolean roaming = (mGsmRoaming || mDataRoaming);
749             if ((mGsmRoaming && isSameNamedOperators(mNewSS))
750                     || isOperatorConsideredNonRoaming(mNewSS)) {
751                 roaming = false;
752             }
753             mNewSS.setRoaming(roaming);
754             mNewSS.setEmergencyOnly(mEmergencyOnly);
755             pollStateDone();
756         }
757     }
758
759     private void setSignalStrengthDefaultValues() {
760         mSignalStrength = new SignalStrength(true);
761     }
762
763     /**
764      * A complete "service state" from our perspective is
765      * composed of a handful of separate requests to the radio.
766      *
767      * We make all of these requests at once, but then abandon them
768      * and start over again if the radio notifies us that some
769      * event has changed
770      */
771     private void pollState() {
772         mPollingContext = new int[1];
773         mPollingContext[0] = 0;
774
775         switch (mCi.getRadioState()) {
776             case RADIO_UNAVAILABLE:
777                 mNewSS.setStateOutOfService();
778                 mNewCellLoc.setStateInvalid();
779                 setSignalStrengthDefaultValues();
780                 mGotCountryCode = false;
781                 mNitzUpdatedTime = false;
782                 pollStateDone();
783             break;
784
785             case RADIO_OFF:
786                 mNewSS.setStateOff();
787                 mNewCellLoc.setStateInvalid();
788                 setSignalStrengthDefaultValues();
789                 mGotCountryCode = false;
790                 mNitzUpdatedTime = false;
791                 pollStateDone();
792             break;
793
794             default:
795                 // Issue all poll-related commands at once
796                 // then count down the responses, which
797                 // are allowed to arrive out-of-order
798
799                 mPollingContext[0]++;
800                 mCi.getOperator(
801                     obtainMessage(
802                         EVENT_POLL_STATE_OPERATOR, mPollingContext));
803
804                 mPollingContext[0]++;
805                 mCi.getDataRegistrationState(
806                     obtainMessage(
807                         EVENT_POLL_STATE_GPRS, mPollingContext));
808
809                 mPollingContext[0]++;
810                 mCi.getVoiceRegistrationState(
811                     obtainMessage(
812                         EVENT_POLL_STATE_REGISTRATION, mPollingContext));
813
814                 mPollingContext[0]++;
815                 mCi.getNetworkSelectionMode(
816                     obtainMessage(
817                         EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));
818             break;
819         }
820     }
821
822     private void pollStateDone() {
823         if (DBG) {
824             log("Poll ServiceState done: " +
825                 " oldSS=[" + mSS + "] newSS=[" + mNewSS + "]" +
826                 " oldMaxDataCalls=" + mMaxDataCalls +
827                 " mNewMaxDataCalls=" + mNewMaxDataCalls +
828                 " oldReasonDataDenied=" + mReasonDataDenied +
829                 " mNewReasonDataDenied=" + mNewReasonDataDenied);
830         }
831
832         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
833             mNewSS.setRoaming(true);
834         }
835
836         useDataRegStateForDataOnlyDevices();
837
838         boolean hasRegistered =
839             mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
840             && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
841
842         boolean hasDeregistered =
843             mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
844             && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
845
846         boolean hasGprsAttached =
847                 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
848                 && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
849
850         boolean hasGprsDetached =
851                 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
852                 && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
853
854         boolean hasDataRegStateChanged =
855                 mSS.getDataRegState() != mNewSS.getDataRegState();
856
857         boolean hasVoiceRegStateChanged =
858                 mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
859
860         boolean hasRilVoiceRadioTechnologyChanged =
861                 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
862
863         boolean hasRilDataRadioTechnologyChanged =
864                 mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
865
866         boolean hasChanged = !mNewSS.equals(mSS);
867
868         boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
869
870         boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
871
872         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
873
874         // Add an event log when connection state changes
875         if (hasVoiceRegStateChanged || hasDataRegStateChanged) {
876             EventLog.writeEvent(EventLogTags.GSM_SERVICE_STATE_CHANGE,
877                 mSS.getVoiceRegState(), mSS.getDataRegState(),
878                 mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
879         }
880
881         // Add an event log when network type switched
882         // TODO: we may add filtering to reduce the event logged,
883         // i.e. check preferred network setting, only switch to 2G, etc
884         if (hasRilVoiceRadioTechnologyChanged) {
885             int cid = -1;
886             GsmCellLocation loc = mNewCellLoc;
887             if (loc != null) cid = loc.getCid();
888             // NOTE: this code was previously located after mSS and mNewSS are swapped, so
889             // existing logs were incorrectly using the new state for "network_from"
890             // and STATE_OUT_OF_SERVICE for "network_to". To avoid confusion, use a new log tag
891             // to record the correct states.
892             EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED_NEW, cid,
893                     mSS.getRilVoiceRadioTechnology(),
894                     mNewSS.getRilVoiceRadioTechnology());
895             if (DBG) {
896                 log("RAT switched "
897                         + ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology())
898                         + " -> "
899                         + ServiceState.rilRadioTechnologyToString(
900                                 mNewSS.getRilVoiceRadioTechnology()) + " at cell " + cid);
901             }
902         }
903
904         // swap mSS and mNewSS to put new state in mSS
905         ServiceState tss = mSS;
906         mSS = mNewSS;
907         mNewSS = tss;
908         // clean slate for next time
909         mNewSS.setStateOutOfService();
910
911         // swap mCellLoc and mNewCellLoc to put new state in mCellLoc
912         GsmCellLocation tcl = mCellLoc;
913         mCellLoc = mNewCellLoc;
914         mNewCellLoc = tcl;
915
916         mReasonDataDenied = mNewReasonDataDenied;
917         mMaxDataCalls = mNewMaxDataCalls;
918
919         if (hasRilVoiceRadioTechnologyChanged) {
920             updatePhoneObject();
921         }
922
923         if (hasRilDataRadioTechnologyChanged) {
924             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
925                     ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology()));
926         }
927
928         if (hasRegistered) {
929             mNetworkAttachedRegistrants.notifyRegistrants();
930
931             if (DBG) {
932                 log("pollStateDone: registering current mNitzUpdatedTime=" +
933                         mNitzUpdatedTime + " changing to false");
934             }
935             mNitzUpdatedTime = false;
936         }
937
938         if (hasChanged) {
939             String operatorNumeric;
940
941             updateSpnDisplay();
942
943             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
944                 mSS.getOperatorAlphaLong());
945
946             String prevOperatorNumeric =
947                     SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
948             operatorNumeric = mSS.getOperatorNumeric();
949             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
950
951             if (operatorNumeric == null) {
952                 if (DBG) log("operatorNumeric is null");
953                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
954                 mGotCountryCode = false;
955                 mNitzUpdatedTime = false;
956             } else {
957                 String iso = "";
958                 String mcc = "";
959                 try{
960                     mcc = operatorNumeric.substring(0, 3);
961                     iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc));
962                 } catch ( NumberFormatException ex){
963                     loge("pollStateDone: countryCodeForMcc error" + ex);
964                 } catch ( StringIndexOutOfBoundsException ex) {
965                     loge("pollStateDone: countryCodeForMcc error" + ex);
966                 }
967
968                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso);
969                 mGotCountryCode = true;
970
971                 TimeZone zone = null;
972
973                 if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) &&
974                         getAutoTimeZone()) {
975
976                     // Test both paths if ignore nitz is true
977                     boolean testOneUniqueOffsetPath = SystemProperties.getBoolean(
978                                 TelephonyProperties.PROPERTY_IGNORE_NITZ, false) &&
979                                     ((SystemClock.uptimeMillis() & 1) == 0);
980
981                     ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso);
982                     if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) {
983                         zone = uniqueZones.get(0);
984                         if (DBG) {
985                            log("pollStateDone: no nitz but one TZ for iso-cc=" + iso +
986                                    " with zone.getID=" + zone.getID() +
987                                    " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
988                         }
989                         setAndBroadcastNetworkSetTimeZone(zone.getID());
990                     } else {
991                         if (DBG) {
992                             log("pollStateDone: there are " + uniqueZones.size() +
993                                 " unique offsets for iso-cc='" + iso +
994                                 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath +
995                                 "', do nothing");
996                         }
997                     }
998                 }
999
1000                 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
1001                         mNeedFixZoneAfterNitz)) {
1002                     // If the offset is (0, false) and the timezone property
1003                     // is set, use the timezone property rather than
1004                     // GMT.
1005                     String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
1006                     if (DBG) {
1007                         log("pollStateDone: fix time zone zoneName='" + zoneName +
1008                             "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
1009                             " iso-cc='" + iso +
1010                             "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso));
1011                     }
1012
1013                     // "(mZoneOffset == 0) && (mZoneDst == false) &&
1014                     //  (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)"
1015                     // means that we received a NITZ string telling
1016                     // it is in GMT+0 w/ DST time zone
1017                     // BUT iso tells is NOT, e.g, a wrong NITZ reporting
1018                     // local time w/ 0 offset.
1019                     if ((mZoneOffset == 0) && (mZoneDst == false) &&
1020                         (zoneName != null) && (zoneName.length() > 0) &&
1021                         (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) {
1022                         zone = TimeZone.getDefault();
1023                         if (mNeedFixZoneAfterNitz) {
1024                             // For wrong NITZ reporting local time w/ 0 offset,
1025                             // need adjust time to reflect default timezone setting
1026                             long ctm = System.currentTimeMillis();
1027                             long tzOffset = zone.getOffset(ctm);
1028                             if (DBG) {
1029                                 log("pollStateDone: tzOffset=" + tzOffset + " ltod=" +
1030                                         TimeUtils.logTimeOfDay(ctm));
1031                             }
1032                             if (getAutoTime()) {
1033                                 long adj = ctm - tzOffset;
1034                                 if (DBG) log("pollStateDone: adj ltod=" +
1035                                         TimeUtils.logTimeOfDay(adj));
1036                                 setAndBroadcastNetworkSetTime(adj);
1037                             } else {
1038                                 // Adjust the saved NITZ time to account for tzOffset.
1039                                 mSavedTime = mSavedTime - tzOffset;
1040                             }
1041                         }
1042                         if (DBG) log("pollStateDone: using default TimeZone");
1043                     } else if (iso.equals("")){
1044                         // Country code not found.  This is likely a test network.
1045                         // Get a TimeZone based only on the NITZ parameters (best guess).
1046                         zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
1047                         if (DBG) log("pollStateDone: using NITZ TimeZone");
1048                     } else {
1049                         zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, iso);
1050                         if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)");
1051                     }
1052
1053                     mNeedFixZoneAfterNitz = false;
1054
1055                     if (zone != null) {
1056                         log("pollStateDone: zone != null zone.getID=" + zone.getID());
1057                         if (getAutoTimeZone()) {
1058                             setAndBroadcastNetworkSetTimeZone(zone.getID());
1059                         }
1060                         saveNitzTimeZone(zone.getID());
1061                     } else {
1062                         log("pollStateDone: zone == null");
1063                     }
1064                 }
1065             }
1066
1067             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
1068                 mSS.getRoaming() ? "true" : "false");
1069
1070             mPhone.notifyServiceStateChanged(mSS);
1071         }
1072
1073         if (hasGprsAttached) {
1074             mAttachedRegistrants.notifyRegistrants();
1075         }
1076
1077         if (hasGprsDetached) {
1078             mDetachedRegistrants.notifyRegistrants();
1079         }
1080
1081         if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
1082             notifyDataRegStateRilRadioTechnologyChanged();
1083             mPhone.notifyDataConnection(null);
1084         }
1085
1086         if (hasRoamingOn) {
1087             mRoamingOnRegistrants.notifyRegistrants();
1088         }
1089
1090         if (hasRoamingOff) {
1091             mRoamingOffRegistrants.notifyRegistrants();
1092         }
1093
1094         if (hasLocationChanged) {
1095             mPhone.notifyLocationChanged();
1096         }
1097
1098         if (! isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
1099             if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
1100                 mStartedGprsRegCheck = true;
1101
1102                 int check_period = Settings.Global.getInt(
1103                         mPhone.getContext().getContentResolver(),
1104                         Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
1105                         DEFAULT_GPRS_CHECK_PERIOD_MILLIS);
1106                 sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS),
1107                         check_period);
1108             }
1109         } else {
1110             mReportedGprsNoReg = false;
1111         }
1112         // TODO: Add GsmCellIdenity updating, see CdmaLteServiceStateTracker.
1113     }
1114
1115     /**
1116      * Check if GPRS got registered while voice is registered.
1117      *
1118      * @param dataRegState i.e. CGREG in GSM
1119      * @param voiceRegState i.e. CREG in GSM
1120      * @return false if device only register to voice but not gprs
1121      */
1122     private boolean isGprsConsistent(int dataRegState, int voiceRegState) {
1123         return !((voiceRegState == ServiceState.STATE_IN_SERVICE) &&
1124                 (dataRegState != ServiceState.STATE_IN_SERVICE));
1125     }
1126
1127     /**
1128      * Returns a TimeZone object based only on parameters from the NITZ string.
1129      */
1130     private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
1131         TimeZone guess = findTimeZone(offset, dst, when);
1132         if (guess == null) {
1133             // Couldn't find a proper timezone.  Perhaps the DST data is wrong.
1134             guess = findTimeZone(offset, !dst, when);
1135         }
1136         if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID()));
1137         return guess;
1138     }
1139
1140     private TimeZone findTimeZone(int offset, boolean dst, long when) {
1141         int rawOffset = offset;
1142         if (dst) {
1143             rawOffset -= 3600000;
1144         }
1145         String[] zones = TimeZone.getAvailableIDs(rawOffset);
1146         TimeZone guess = null;
1147         Date d = new Date(when);
1148         for (String zone : zones) {
1149             TimeZone tz = TimeZone.getTimeZone(zone);
1150             if (tz.getOffset(when) == offset &&
1151                 tz.inDaylightTime(d) == dst) {
1152                 guess = tz;
1153                 break;
1154             }
1155         }
1156
1157         return guess;
1158     }
1159
1160     private void queueNextSignalStrengthPoll() {
1161         if (mDontPollSignalStrength) {
1162             // The radio is telling us about signal strength changes
1163             // we don't have to ask it
1164             return;
1165         }
1166
1167         Message msg;
1168
1169         msg = obtainMessage();
1170         msg.what = EVENT_POLL_SIGNAL_STRENGTH;
1171
1172         long nextTime;
1173
1174         // TODO Don't poll signal strength if screen is off
1175         sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
1176     }
1177
1178     /**
1179      * Set restricted state based on the OnRestrictedStateChanged notification
1180      * If any voice or packet restricted state changes, trigger a UI
1181      * notification and notify registrants when sim is ready.
1182      *
1183      * @param ar an int value of RIL_RESTRICTED_STATE_*
1184      */
1185     private void onRestrictedStateChanged(AsyncResult ar) {
1186         RestrictedState newRs = new RestrictedState();
1187
1188         if (DBG) log("onRestrictedStateChanged: E rs "+ mRestrictedState);
1189
1190         if (ar.exception == null) {
1191             int[] ints = (int[])ar.result;
1192             int state = ints[0];
1193
1194             newRs.setCsEmergencyRestricted(
1195                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
1196                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
1197             //ignore the normal call and data restricted state before SIM READY
1198             if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY) {
1199                 newRs.setCsNormalRestricted(
1200                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
1201                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
1202                 newRs.setPsRestricted(
1203                         (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0);
1204             }
1205
1206             if (DBG) log("onRestrictedStateChanged: new rs "+ newRs);
1207
1208             if (!mRestrictedState.isPsRestricted() && newRs.isPsRestricted()) {
1209                 mPsRestrictEnabledRegistrants.notifyRegistrants();
1210                 setNotification(PS_ENABLED);
1211             } else if (mRestrictedState.isPsRestricted() && !newRs.isPsRestricted()) {
1212                 mPsRestrictDisabledRegistrants.notifyRegistrants();
1213                 setNotification(PS_DISABLED);
1214             }
1215
1216             /**
1217              * There are two kind of cs restriction, normal and emergency. So
1218              * there are 4 x 4 combinations in current and new restricted states
1219              * and we only need to notify when state is changed.
1220              */
1221             if (mRestrictedState.isCsRestricted()) {
1222                 if (!newRs.isCsRestricted()) {
1223                     // remove all restriction
1224                     setNotification(CS_DISABLED);
1225                 } else if (!newRs.isCsNormalRestricted()) {
1226                     // remove normal restriction
1227                     setNotification(CS_EMERGENCY_ENABLED);
1228                 } else if (!newRs.isCsEmergencyRestricted()) {
1229                     // remove emergency restriction
1230                     setNotification(CS_NORMAL_ENABLED);
1231                 }
1232             } else if (mRestrictedState.isCsEmergencyRestricted() &&
1233                     !mRestrictedState.isCsNormalRestricted()) {
1234                 if (!newRs.isCsRestricted()) {
1235                     // remove all restriction
1236                     setNotification(CS_DISABLED);
1237                 } else if (newRs.isCsRestricted()) {
1238                     // enable all restriction
1239                     setNotification(CS_ENABLED);
1240                 } else if (newRs.isCsNormalRestricted()) {
1241                     // remove emergency restriction and enable normal restriction
1242                     setNotification(CS_NORMAL_ENABLED);
1243                 }
1244             } else if (!mRestrictedState.isCsEmergencyRestricted() &&
1245                     mRestrictedState.isCsNormalRestricted()) {
1246                 if (!newRs.isCsRestricted()) {
1247                     // remove all restriction
1248                     setNotification(CS_DISABLED);
1249                 } else if (newRs.isCsRestricted()) {
1250                     // enable all restriction
1251                     setNotification(CS_ENABLED);
1252                 } else if (newRs.isCsEmergencyRestricted()) {
1253                     // remove normal restriction and enable emergency restriction
1254                     setNotification(CS_EMERGENCY_ENABLED);
1255                 }
1256             } else {
1257                 if (newRs.isCsRestricted()) {
1258                     // enable all restriction
1259                     setNotification(CS_ENABLED);
1260                 } else if (newRs.isCsEmergencyRestricted()) {
1261                     // enable emergency restriction
1262                     setNotification(CS_EMERGENCY_ENABLED);
1263                 } else if (newRs.isCsNormalRestricted()) {
1264                     // enable normal restriction
1265                     setNotification(CS_NORMAL_ENABLED);
1266                 }
1267             }
1268
1269             mRestrictedState = newRs;
1270         }
1271         log("onRestrictedStateChanged: X rs "+ mRestrictedState);
1272     }
1273
1274     /** code is registration state 0-5 from TS 27.007 7.2 */
1275     private int regCodeToServiceState(int code) {
1276         switch (code) {
1277             case 0:
1278             case 2: // 2 is "searching"
1279             case 3: // 3 is "registration denied"
1280             case 4: // 4 is "unknown" no vaild in current baseband
1281             case 10:// same as 0, but indicates that emergency call is possible.
1282             case 12:// same as 2, but indicates that emergency call is possible.
1283             case 13:// same as 3, but indicates that emergency call is possible.
1284             case 14:// same as 4, but indicates that emergency call is possible.
1285                 return ServiceState.STATE_OUT_OF_SERVICE;
1286
1287             case 1:
1288                 return ServiceState.STATE_IN_SERVICE;
1289
1290             case 5:
1291                 // in service, roam
1292                 return ServiceState.STATE_IN_SERVICE;
1293
1294             default:
1295                 loge("regCodeToServiceState: unexpected service state " + code);
1296                 return ServiceState.STATE_OUT_OF_SERVICE;
1297         }
1298     }
1299
1300
1301     /**
1302      * code is registration state 0-5 from TS 27.007 7.2
1303      * returns true if registered roam, false otherwise
1304      */
1305     private boolean regCodeIsRoaming (int code) {
1306         return ServiceState.RIL_REG_STATE_ROAMING == code;
1307     }
1308
1309     /**
1310      * Set roaming state if operator mcc is the same as sim mcc
1311      * and ons is different from spn
1312      *
1313      * @param s ServiceState hold current ons
1314      * @return true if same operator
1315      */
1316     private boolean isSameNamedOperators(ServiceState s) {
1317         String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty");
1318
1319         String onsl = s.getOperatorAlphaLong();
1320         String onss = s.getOperatorAlphaShort();
1321
1322         boolean equalsOnsl = onsl != null && spn.equals(onsl);
1323         boolean equalsOnss = onss != null && spn.equals(onss);
1324
1325         return currentMccEqualsSimMcc(s) && (equalsOnsl || equalsOnss);
1326     }
1327
1328     /**
1329      * Compare SIM MCC with Operator MCC
1330      *
1331      * @param s ServiceState hold current ons
1332      * @return true if both are same
1333      */
1334     private boolean currentMccEqualsSimMcc(ServiceState s) {
1335         String simNumeric = SystemProperties.get(
1336                 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
1337         String operatorNumeric = s.getOperatorNumeric();
1338         boolean equalsMcc = true;
1339
1340         try {
1341             equalsMcc = simNumeric.substring(0, 3).
1342                     equals(operatorNumeric.substring(0, 3));
1343         } catch (Exception e){
1344         }
1345         return equalsMcc;
1346     }
1347
1348     /**
1349      * Do not set roaming state in case of oprators considered non-roaming.
1350      *
1351      + Can use mcc or mcc+mnc as item of config_operatorConsideredNonRoaming.
1352      * For example, 302 or 21407. If mcc or mcc+mnc match with operator,
1353      * don't set roaming state.
1354      *
1355      * @param s ServiceState hold current ons
1356      * @return false for roaming state set
1357      */
1358     private boolean isOperatorConsideredNonRoaming(ServiceState s) {
1359         String operatorNumeric = s.getOperatorNumeric();
1360         String[] numericArray = mPhone.getContext().getResources().getStringArray(
1361                     com.android.internal.R.array.config_operatorConsideredNonRoaming);
1362
1363         if (numericArray.length == 0 || operatorNumeric == null)
1364             return false;
1365
1366         for (String numeric : numericArray) {
1367             if (operatorNumeric.startsWith(numeric))
1368                 return true;
1369             else
1370                 return false;
1371         }
1372         return false;
1373     }
1374
1375     /**
1376      * @return The current GPRS state. IN_SERVICE is the same as "attached"
1377      * and OUT_OF_SERVICE is the same as detached.
1378      */
1379     @Override
1380     public int getCurrentDataConnectionState() {
1381         return mSS.getDataRegState();
1382     }
1383
1384     /**
1385      * @return true if phone is camping on a technology (eg UMTS)
1386      * that could support voice and data simultaneously.
1387      */
1388     @Override
1389     public boolean isConcurrentVoiceAndDataAllowed() {
1390         return (mSS.getRilVoiceRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
1391     }
1392
1393     /**
1394      * @return the current cell location information. Prefer Gsm location
1395      * information if available otherwise return LTE location information
1396      */
1397     public CellLocation getCellLocation() {
1398         if ((mCellLoc.getLac() >= 0) && (mCellLoc.getCid() >= 0)) {
1399             if (DBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc);
1400             return mCellLoc;
1401         } else {
1402             List<CellInfo> result = getAllCellInfo();
1403             if (result != null) {
1404                 // A hack to allow tunneling of LTE information via GsmCellLocation
1405                 // so that older Network Location Providers can return some information
1406                 // on LTE only networks, see bug 9228974.
1407                 //
1408                 // We'll search the return CellInfo array preferring GSM/WCDMA
1409                 // data, but if there is none we'll tunnel the first LTE information
1410                 // in the list.
1411                 //
1412                 // The tunnel'd LTE information is returned as follows:
1413                 //   LAC = TAC field
1414                 //   CID = CI field
1415                 //   PSC = 0.
1416                 GsmCellLocation cellLocOther = new GsmCellLocation();
1417                 for (CellInfo ci : result) {
1418                     if (ci instanceof CellInfoGsm) {
1419                         CellInfoGsm cellInfoGsm = (CellInfoGsm)ci;
1420                         CellIdentityGsm cellIdentityGsm = cellInfoGsm.getCellIdentity();
1421                         cellLocOther.setLacAndCid(cellIdentityGsm.getLac(),
1422                                 cellIdentityGsm.getCid());
1423                         cellLocOther.setPsc(cellIdentityGsm.getPsc());
1424                         if (DBG) log("getCellLocation(): X ret GSM info=" + cellLocOther);
1425                         return cellLocOther;
1426                     } else if (ci instanceof CellInfoWcdma) {
1427                         CellInfoWcdma cellInfoWcdma = (CellInfoWcdma)ci;
1428                         CellIdentityWcdma cellIdentityWcdma = cellInfoWcdma.getCellIdentity();
1429                         cellLocOther.setLacAndCid(cellIdentityWcdma.getLac(),
1430                                 cellIdentityWcdma.getCid());
1431                         cellLocOther.setPsc(cellIdentityWcdma.getPsc());
1432                         if (DBG) log("getCellLocation(): X ret WCDMA info=" + cellLocOther);
1433                         return cellLocOther;
1434                     } else if ((ci instanceof CellInfoLte) &&
1435                             ((cellLocOther.getLac() < 0) || (cellLocOther.getCid() < 0))) {
1436                         // We'll return the first good LTE info we get if there is no better answer
1437                         CellInfoLte cellInfoLte = (CellInfoLte)ci;
1438                         CellIdentityLte cellIdentityLte = cellInfoLte.getCellIdentity();
1439                         if ((cellIdentityLte.getTac() != Integer.MAX_VALUE)
1440                                 && (cellIdentityLte.getCi() != Integer.MAX_VALUE)) {
1441                             cellLocOther.setLacAndCid(cellIdentityLte.getTac(),
1442                                     cellIdentityLte.getCi());
1443                             cellLocOther.setPsc(0);
1444                             if (DBG) {
1445                                 log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther);
1446                             }
1447                         }
1448                     }
1449                 }
1450                 if (DBG) {
1451                     log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther);
1452                 }
1453                 return cellLocOther;
1454             } else {
1455                 if (DBG) {
1456                     log("getCellLocation(): X empty mCellLoc and CellInfo mCellLoc=" + mCellLoc);
1457                 }
1458                 return mCellLoc;
1459             }
1460         }
1461     }
1462
1463     /**
1464      * nitzReceiveTime is time_t that the NITZ time was posted
1465      */
1466     private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {
1467         // "yy/mm/dd,hh:mm:ss(+/-)tz"
1468         // tz is in number of quarter-hours
1469
1470         long start = SystemClock.elapsedRealtime();
1471         if (DBG) {log("NITZ: " + nitz + "," + nitzReceiveTime +
1472                         " start=" + start + " delay=" + (start - nitzReceiveTime));
1473         }
1474
1475         try {
1476             /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
1477              * offset as well (which we won't worry about until later) */
1478             Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
1479
1480             c.clear();
1481             c.set(Calendar.DST_OFFSET, 0);
1482
1483             String[] nitzSubs = nitz.split("[/:,+-]");
1484
1485             int year = 2000 + Integer.parseInt(nitzSubs[0]);
1486             c.set(Calendar.YEAR, year);
1487
1488             // month is 0 based!
1489             int month = Integer.parseInt(nitzSubs[1]) - 1;
1490             c.set(Calendar.MONTH, month);
1491
1492             int date = Integer.parseInt(nitzSubs[2]);
1493             c.set(Calendar.DATE, date);
1494
1495             int hour = Integer.parseInt(nitzSubs[3]);
1496             c.set(Calendar.HOUR, hour);
1497
1498             int minute = Integer.parseInt(nitzSubs[4]);
1499             c.set(Calendar.MINUTE, minute);
1500
1501             int second = Integer.parseInt(nitzSubs[5]);
1502             c.set(Calendar.SECOND, second);
1503
1504             boolean sign = (nitz.indexOf('-') == -1);
1505
1506             int tzOffset = Integer.parseInt(nitzSubs[6]);
1507
1508             int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
1509                                               : 0;
1510
1511             // The zone offset received from NITZ is for current local time,
1512             // so DST correction is already applied.  Don't add it again.
1513             //
1514             // tzOffset += dst * 4;
1515             //
1516             // We could unapply it if we wanted the raw offset.
1517
1518             tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
1519
1520             TimeZone    zone = null;
1521
1522             // As a special extension, the Android emulator appends the name of
1523             // the host computer's timezone to the nitz string. this is zoneinfo
1524             // timezone name of the form Area!Location or Area!Location!SubLocation
1525             // so we need to convert the ! into /
1526             if (nitzSubs.length >= 9) {
1527                 String  tzname = nitzSubs[8].replace('!','/');
1528                 zone = TimeZone.getTimeZone( tzname );
1529             }
1530
1531             String iso = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
1532
1533             if (zone == null) {
1534
1535                 if (mGotCountryCode) {
1536                     if (iso != null && iso.length() > 0) {
1537                         zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
1538                                 c.getTimeInMillis(),
1539                                 iso);
1540                     } else {
1541                         // We don't have a valid iso country code.  This is
1542                         // most likely because we're on a test network that's
1543                         // using a bogus MCC (eg, "001"), so get a TimeZone
1544                         // based only on the NITZ parameters.
1545                         zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
1546                     }
1547                 }
1548             }
1549
1550             if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){
1551                 // We got the time before the country or the zone has changed
1552                 // so we don't know how to identify the DST rules yet.  Save
1553                 // the information and hope to fix it up later.
1554
1555                 mNeedFixZoneAfterNitz = true;
1556                 mZoneOffset  = tzOffset;
1557                 mZoneDst     = dst != 0;
1558                 mZoneTime    = c.getTimeInMillis();
1559             }
1560
1561             if (zone != null) {
1562                 if (getAutoTimeZone()) {
1563                     setAndBroadcastNetworkSetTimeZone(zone.getID());
1564                 }
1565                 saveNitzTimeZone(zone.getID());
1566             }
1567
1568             String ignore = SystemProperties.get("gsm.ignore-nitz");
1569             if (ignore != null && ignore.equals("yes")) {
1570                 log("NITZ: Not setting clock because gsm.ignore-nitz is set");
1571                 return;
1572             }
1573
1574             try {
1575                 mWakeLock.acquire();
1576
1577                 if (getAutoTime()) {
1578                     long millisSinceNitzReceived
1579                             = SystemClock.elapsedRealtime() - nitzReceiveTime;
1580
1581                     if (millisSinceNitzReceived < 0) {
1582                         // Sanity check: something is wrong
1583                         if (DBG) {
1584                             log("NITZ: not setting time, clock has rolled "
1585                                             + "backwards since NITZ time was received, "
1586                                             + nitz);
1587                         }
1588                         return;
1589                     }
1590
1591                     if (millisSinceNitzReceived > Integer.MAX_VALUE) {
1592                         // If the time is this far off, something is wrong > 24 days!
1593                         if (DBG) {
1594                             log("NITZ: not setting time, processing has taken "
1595                                         + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
1596                                         + " days");
1597                         }
1598                         return;
1599                     }
1600
1601                     // Note: with range checks above, cast to int is safe
1602                     c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
1603
1604                     if (DBG) {
1605                         log("NITZ: Setting time of day to " + c.getTime()
1606                             + " NITZ receive delay(ms): " + millisSinceNitzReceived
1607                             + " gained(ms): "
1608                             + (c.getTimeInMillis() - System.currentTimeMillis())
1609                             + " from " + nitz);
1610                     }
1611
1612                     setAndBroadcastNetworkSetTime(c.getTimeInMillis());
1613                     Rlog.i(LOG_TAG, "NITZ: after Setting time of day");
1614                 }
1615                 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
1616                 saveNitzTime(c.getTimeInMillis());
1617                 if (VDBG) {
1618                     long end = SystemClock.elapsedRealtime();
1619                     log("NITZ: end=" + end + " dur=" + (end - start));
1620                 }
1621                 mNitzUpdatedTime = true;
1622             } finally {
1623                 mWakeLock.release();
1624             }
1625         } catch (RuntimeException ex) {
1626             loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
1627         }
1628     }
1629
1630     private boolean getAutoTime() {
1631         try {
1632             return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1633                     Settings.Global.AUTO_TIME) > 0;
1634         } catch (SettingNotFoundException snfe) {
1635             return true;
1636         }
1637     }
1638
1639     private boolean getAutoTimeZone() {
1640         try {
1641             return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1642                     Settings.Global.AUTO_TIME_ZONE) > 0;
1643         } catch (SettingNotFoundException snfe) {
1644             return true;
1645         }
1646     }
1647
1648     private void saveNitzTimeZone(String zoneId) {
1649         mSavedTimeZone = zoneId;
1650     }
1651
1652     private void saveNitzTime(long time) {
1653         mSavedTime = time;
1654         mSavedAtTime = SystemClock.elapsedRealtime();
1655     }
1656
1657     /**
1658      * Set the timezone and send out a sticky broadcast so the system can
1659      * determine if the timezone was set by the carrier.
1660      *
1661      * @param zoneId timezone set by carrier
1662      */
1663     private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
1664         if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId);
1665         AlarmManager alarm =
1666             (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
1667         alarm.setTimeZone(zoneId);
1668         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
1669         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1670         intent.putExtra("time-zone", zoneId);
1671         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1672         if (DBG) {
1673             log("setAndBroadcastNetworkSetTimeZone: call alarm.setTimeZone and broadcast zoneId=" +
1674                 zoneId);
1675         }
1676     }
1677
1678     /**
1679      * Set the time and Send out a sticky broadcast so the system can determine
1680      * if the time was set by the carrier.
1681      *
1682      * @param time time set by network
1683      */
1684     private void setAndBroadcastNetworkSetTime(long time) {
1685         if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
1686         SystemClock.setCurrentTimeMillis(time);
1687         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
1688         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1689         intent.putExtra("time", time);
1690         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1691     }
1692
1693     private void revertToNitzTime() {
1694         if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1695                 Settings.Global.AUTO_TIME, 0) == 0) {
1696             return;
1697         }
1698         if (DBG) {
1699             log("Reverting to NITZ Time: mSavedTime=" + mSavedTime
1700                 + " mSavedAtTime=" + mSavedAtTime);
1701         }
1702         if (mSavedTime != 0 && mSavedAtTime != 0) {
1703             setAndBroadcastNetworkSetTime(mSavedTime
1704                     + (SystemClock.elapsedRealtime() - mSavedAtTime));
1705         }
1706     }
1707
1708     private void revertToNitzTimeZone() {
1709         if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1710                 Settings.Global.AUTO_TIME_ZONE, 0) == 0) {
1711             return;
1712         }
1713         if (DBG) log("Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);
1714         if (mSavedTimeZone != null) {
1715             setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
1716         }
1717     }
1718
1719     /**
1720      * Post a notification to NotificationManager for restricted state
1721      *
1722      * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE
1723      */
1724     private void setNotification(int notifyType) {
1725
1726         if (DBG) log("setNotification: create notification " + notifyType);
1727         Context context = mPhone.getContext();
1728
1729         mNotification = new Notification();
1730         mNotification.when = System.currentTimeMillis();
1731         mNotification.flags = Notification.FLAG_AUTO_CANCEL;
1732         mNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
1733         Intent intent = new Intent();
1734         mNotification.contentIntent = PendingIntent
1735         .getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
1736
1737         CharSequence details = "";
1738         CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle);
1739         int notificationId = CS_NOTIFICATION;
1740
1741         switch (notifyType) {
1742         case PS_ENABLED:
1743             notificationId = PS_NOTIFICATION;
1744             details = context.getText(com.android.internal.R.string.RestrictedOnData);
1745             break;
1746         case PS_DISABLED:
1747             notificationId = PS_NOTIFICATION;
1748             break;
1749         case CS_ENABLED:
1750             details = context.getText(com.android.internal.R.string.RestrictedOnAllVoice);
1751             break;
1752         case CS_NORMAL_ENABLED:
1753             details = context.getText(com.android.internal.R.string.RestrictedOnNormal);
1754             break;
1755         case CS_EMERGENCY_ENABLED:
1756             details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);
1757             break;
1758         case CS_DISABLED:
1759             // do nothing and cancel the notification later
1760             break;
1761         }
1762
1763         if (DBG) log("setNotification: put notification " + title + " / " +details);
1764         mNotification.tickerText = title;
1765         mNotification.setLatestEventInfo(context, title, details,
1766                 mNotification.contentIntent);
1767
1768         NotificationManager notificationManager = (NotificationManager)
1769             context.getSystemService(Context.NOTIFICATION_SERVICE);
1770
1771         if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) {
1772             // cancel previous post notification
1773             notificationManager.cancel(notificationId);
1774         } else {
1775             // update restricted state notification
1776             notificationManager.notify(notificationId, mNotification);
1777         }
1778     }
1779
1780     @Override
1781     protected void onUpdateIccAvailability() {
1782         if (mUiccController == null ) {
1783             return;
1784         }
1785
1786         UiccCardApplication newUiccApplication =
1787                 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);
1788
1789         if (mUiccApplcation != newUiccApplication) {
1790             if (mUiccApplcation != null) {
1791                 log("Removing stale icc objects.");
1792                 mUiccApplcation.unregisterForReady(this);
1793                 if (mIccRecords != null) {
1794                     mIccRecords.unregisterForRecordsLoaded(this);
1795                 }
1796                 mIccRecords = null;
1797                 mUiccApplcation = null;
1798             }
1799             if (newUiccApplication != null) {
1800                 log("New card found");
1801                 mUiccApplcation = newUiccApplication;
1802                 mIccRecords = mUiccApplcation.getIccRecords();
1803                 mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);
1804                 if (mIccRecords != null) {
1805                     mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
1806                 }
1807             }
1808         }
1809     }
1810     @Override
1811     protected void log(String s) {
1812         Rlog.d(LOG_TAG, "[GsmSST] " + s);
1813     }
1814
1815     @Override
1816     protected void loge(String s) {
1817         Rlog.e(LOG_TAG, "[GsmSST] " + s);
1818     }
1819
1820     @Override
1821     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1822         pw.println("GsmServiceStateTracker extends:");
1823         super.dump(fd, pw, args);
1824         pw.println(" mPhone=" + mPhone);
1825         pw.println(" mSS=" + mSS);
1826         pw.println(" mNewSS=" + mNewSS);
1827         pw.println(" mCellLoc=" + mCellLoc);
1828         pw.println(" mNewCellLoc=" + mNewCellLoc);
1829         pw.println(" mPreferredNetworkType=" + mPreferredNetworkType);
1830         pw.println(" mMaxDataCalls=" + mMaxDataCalls);
1831         pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls);
1832         pw.println(" mReasonDataDenied=" + mReasonDataDenied);
1833         pw.println(" mNewReasonDataDenied=" + mNewReasonDataDenied);
1834         pw.println(" mGsmRoaming=" + mGsmRoaming);
1835         pw.println(" mDataRoaming=" + mDataRoaming);
1836         pw.println(" mEmergencyOnly=" + mEmergencyOnly);
1837         pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz);
1838         pw.println(" mZoneOffset=" + mZoneOffset);
1839         pw.println(" mZoneDst=" + mZoneDst);
1840         pw.println(" mZoneTime=" + mZoneTime);
1841         pw.println(" mGotCountryCode=" + mGotCountryCode);
1842         pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime);
1843         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
1844         pw.println(" mSavedTime=" + mSavedTime);
1845         pw.println(" mSavedAtTime=" + mSavedAtTime);
1846         pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
1847         pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
1848         pw.println(" mNotification=" + mNotification);
1849         pw.println(" mWakeLock=" + mWakeLock);
1850         pw.println(" mCurSpn=" + mCurSpn);
1851         pw.println(" mCurShowSpn=" + mCurShowSpn);
1852         pw.println(" mCurPlmn=" + mCurPlmn);
1853         pw.println(" mCurShowPlmn=" + mCurShowPlmn);
1854     }
1855 }