2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.internal.telephony.gsm;
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;
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;
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;
85 final class GsmServiceStateTracker extends ServiceStateTracker {
86 private static final String LOG_TAG = "GsmSST";
87 private static final boolean VDBG = false;
90 GsmCellLocation mCellLoc;
91 GsmCellLocation mNewCellLoc;
92 int mPreferredNetworkType;
94 private int mMaxDataCalls = 1;
95 private int mNewMaxDataCalls = 1;
96 private int mReasonDataDenied = -1;
97 private int mNewReasonDataDenied = -1;
100 * GSM roaming status solely based on TS 27.007 7.2 CREG. Only used by
101 * handlePollStateResult to store CREG roaming result.
103 private boolean mGsmRoaming = false;
106 * Data roaming status solely based on TS 27.007 10.1.19 CGREG. Only used by
107 * handlePollStateResult to store CGREG roaming result.
109 private boolean mDataRoaming = false;
112 * Mark when service state is in emergency call only mode
114 private boolean mEmergencyOnly = false;
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.
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;
128 /** Boolean is true is setTimeFromNITZString was called */
129 private boolean mNitzUpdatedTime = false;
131 String mSavedTimeZone;
135 /** Started the recheck process after finding gprs should registered but not. */
136 private boolean mStartedGprsRegCheck = false;
138 /** Already sent the event-log for no gprs register. */
139 private boolean mReportedGprsNoReg = false;
142 * The Notification object given to the NotificationManager.
144 private Notification mNotification;
146 /** Wake lock used while setting time of day. */
147 private PowerManager.WakeLock mWakeLock;
148 private static final String WAKELOCK_TAG = "ServiceStateTracker";
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;
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
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
168 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
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.");
177 if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
178 // update emergency string whenever locale changed
184 private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
186 public void onChange(boolean selfChange) {
187 Rlog.i("GsmServiceStateTracker", "Auto time state changed");
192 private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
194 public void onChange(boolean selfChange) {
195 Rlog.i("GsmServiceStateTracker", "Auto time zone state changed");
196 revertToNitzTimeZone();
200 public GsmServiceStateTracker(GSMPhone phone) {
201 super(phone, phone.mCi, new CellInfoGsm());
204 mCellLoc = new GsmCellLocation();
205 mNewCellLoc = new GsmCellLocation();
207 PowerManager powerManager =
208 (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
209 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
211 mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
212 mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
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);
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);
224 mCr = phone.getContext().getContentResolver();
225 mCr.registerContentObserver(
226 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
228 mCr.registerContentObserver(
229 Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
230 mAutoTimeZoneObserver);
232 setSignalStrengthDefaultValues();
234 // Monitor locale change
235 IntentFilter filter = new IntentFilter();
236 filter.addAction(Intent.ACTION_LOCALE_CHANGED);
237 phone.getContext().registerReceiver(mIntentReceiver, filter);
239 // Gsm doesn't support OTASP so its not needed
240 phone.notifyOtaspChanged(OTASP_NOT_NEEDED);
244 public void dispose() {
245 checkCorrectThread();
246 log("ServiceStateTracker dispose");
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);
263 protected void finalize() {
264 if(DBG) log("finalize");
268 protected Phone getPhone() {
273 public void handleMessage (Message msg) {
279 if (!mPhone.mIsTheCurrentActivePhone) {
280 Rlog.e(LOG_TAG, "Received message " + msg +
281 "[" + msg.what + "] while being destroyed. Ignoring.");
285 case EVENT_RADIO_AVAILABLE:
286 //this is unnecessary
287 //setPowerStateToDesired();
290 case EVENT_SIM_READY:
291 // Set the network type, in case the radio does not restore it.
292 mCi.setCurrentPreferredNetworkType();
294 boolean skipRestoringSelection = mPhone.getContext().getResources().getBoolean(
295 com.android.internal.R.bool.skip_restoring_network_selection);
297 if (!skipRestoringSelection) {
298 // restore the previous network selection.
299 mPhone.restoreSavedNetworkSelection(null);
302 // Signal strength polling stops when radio is off
303 queueNextSignalStrengthPoll();
306 case EVENT_RADIO_STATE_CHANGED:
307 // This will do nothing in the radio not
309 setPowerStateToDesired();
313 case EVENT_NETWORK_STATE_CHANGED:
317 case EVENT_GET_SIGNAL_STRENGTH:
318 // This callback is called when signal strength is polled
321 if (!(mCi.getRadioState().isOn())) {
322 // Polling will continue when radio turns back on
325 ar = (AsyncResult) msg.obj;
326 onSignalStrengthResult(ar, true);
327 queueNextSignalStrengthPoll();
331 case EVENT_GET_LOC_DONE:
332 ar = (AsyncResult) msg.obj;
334 if (ar.exception == null) {
335 String states[] = (String[])ar.result;
338 if (states.length >= 3) {
340 if (states[1] != null && states[1].length() > 0) {
341 lac = Integer.parseInt(states[1], 16);
343 if (states[2] != null && states[2].length() > 0) {
344 cid = Integer.parseInt(states[2], 16);
346 } catch (NumberFormatException ex) {
347 Rlog.w(LOG_TAG, "error parsing location: " + ex);
350 mCellLoc.setLacAndCid(lac, cid);
351 mPhone.notifyLocationChanged();
354 // Release any temporary cell lock, which could have been
355 // acquired to allow a single-shot location update.
356 disableSingleLocationUpdate();
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;
365 handlePollStateResult(msg.what, ar);
368 case EVENT_POLL_SIGNAL_STRENGTH:
369 // Just poll signal strength...not part of pollState()
371 mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
374 case EVENT_NITZ_TIME:
375 ar = (AsyncResult) msg.obj;
377 String nitzString = (String)((Object[])ar.result)[0];
378 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
380 setTimeFromNITZString(nitzString, nitzReceiveTime);
383 case EVENT_SIGNAL_STRENGTH_UPDATE:
384 // This is a notification from
385 // CommandsInterface.setOnSignalStrengthUpdate
387 ar = (AsyncResult) msg.obj;
389 // The radio is telling us about signal strength changes
390 // we don't have to ask it
391 mDontPollSignalStrength = true;
393 onSignalStrengthResult(ar, true);
396 case EVENT_SIM_RECORDS_LOADED:
397 log("EVENT_SIM_RECORDS_LOADED: what=" + msg.what);
403 case EVENT_LOCATION_UPDATES_ENABLED:
404 ar = (AsyncResult) msg.obj;
406 if (ar.exception == null) {
407 mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null));
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);
418 case EVENT_RESET_PREFERRED_NETWORK_TYPE:
419 ar = (AsyncResult) msg.obj;
420 if (ar.userObj != null) {
421 AsyncResult.forMessage(((Message) ar.userObj)).exception
423 ((Message) ar.userObj).sendToTarget();
427 case EVENT_GET_PREFERRED_NETWORK_TYPE:
428 ar = (AsyncResult) msg.obj;
430 if (ar.exception == null) {
431 mPreferredNetworkType = ((int[])ar.result)[0];
433 mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
436 message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj);
437 int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
439 mCi.setPreferredNetworkType(toggledNetworkType, message);
442 case EVENT_CHECK_REPORT_GPRS:
443 if (mSS != null && !isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
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;
453 mStartedGprsRegCheck = false;
456 case EVENT_RESTRICTED_STATE_CHANGED:
457 // This is a notification from
458 // CommandsInterface.setOnRestrictedStateChanged
460 if (DBG) log("EVENT_RESTRICTED_STATE_CHANGED");
462 ar = (AsyncResult) msg.obj;
464 onRestrictedStateChanged(ar);
468 super.handleMessage(msg);
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
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();
495 mCi.setRadioPower(false, null);
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"
506 // 2) No service at all --> expected to show "No service"
507 // EXTRA_SHOW_PLMN = true
508 // EXTRA_PLMN = "No service"
510 // 3) Normal operation in either home or roaming service
511 // EXTRA_SHOW_PLMN = depending on IccRecords rule
514 // 4) No service due to power off, aka airplane mode
515 // EXTRA_SHOW_PLMN = false
518 IccRecords iccRecords = mIccRecords;
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) {
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();
531 plmn = Resources.getSystem().
532 getText(com.android.internal.R.string.lockscreen_carrier_default).toString();
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);
543 // Power off state, such as airplane mode
544 if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn="
545 + showPlmn + " plmn=" + plmn);
548 // The value of spn/showSpn are same in different scenarios.
549 // EXTRA_SHOW_SPN = depending on IccRecords rule
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);
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)) {
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));
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);
576 mCurShowSpn = showSpn;
577 mCurShowPlmn = showPlmn;
583 * Handle the result of one of the pollState()-related requests
586 protected void handlePollStateResult (int what, AsyncResult ar) {
590 // Ignore stale requests from last poll
591 if (ar.userObj != mPollingContext) return;
593 if (ar.exception != null) {
594 CommandException.Error err=null;
596 if (ar.exception instanceof CommandException) {
597 err = ((CommandException)(ar.exception)).getCommandError();
600 if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
601 // Radio has crashed or turned off
606 if (!mCi.getRadioState().isOn()) {
607 // Radio has crashed or turned off
612 if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
613 loge("RIL implementation has returned an error where it must succeed" +
618 case EVENT_POLL_STATE_REGISTRATION: {
619 states = (String[])ar.result;
622 int type = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
623 int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
624 int reasonRegStateDenied = -1;
626 if (states.length > 0) {
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);
633 if (states[2] != null && states[2].length() > 0) {
634 cid = Integer.parseInt(states[2], 16);
637 // states[3] (if present) is the current radio technology
638 if (states.length >= 4 && states[3] != null) {
639 type = Integer.parseInt(states[3]);
642 if (states.length > 14) {
643 if (states[14] != null && states[14].length() > 0) {
644 psc = Integer.parseInt(states[14], 16);
647 } catch (NumberFormatException ex) {
648 loge("error parsing RegistrationState: " + ex);
652 mGsmRoaming = regCodeIsRoaming(regState);
653 mNewSS.setState(regCodeToServiceState(regState));
654 mNewSS.setRilVoiceRadioTechnology(type);
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)
663 mEmergencyOnly = true;
665 mEmergencyOnly = false;
668 // LAC and CID are -1 if not avail
669 mNewCellLoc.setLacAndCid(lac, cid);
670 mNewCellLoc.setPsc(psc);
674 case EVENT_POLL_STATE_GPRS: {
675 states = (String[])ar.result;
678 int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
679 mNewReasonDataDenied = -1;
680 mNewMaxDataCalls = 1;
681 if (states.length > 0) {
683 regState = Integer.parseInt(states[0]);
685 // states[3] (if present) is the current radio technology
686 if (states.length >= 4 && states[3] != null) {
687 type = Integer.parseInt(states[3]);
689 if ((states.length >= 5 ) &&
690 (regState == ServiceState.RIL_REG_STATE_DENIED)) {
691 mNewReasonDataDenied = Integer.parseInt(states[4]);
693 if (states.length >= 6) {
694 mNewMaxDataCalls = Integer.parseInt(states[5]);
696 } catch (NumberFormatException ex) {
697 loge("error parsing GprsRegistrationState: " + ex);
700 int dataRegState = regCodeToServiceState(regState);
701 mNewSS.setDataRegState(dataRegState);
702 mDataRoaming = regCodeIsRoaming(regState);
703 mNewSS.setRilDataRadioTechnology(type);
705 log("handlPollStateResultMessage: GsmSST setDataRegState=" + dataRegState
706 + " regState=" + regState
707 + " dataRadioTechnology=" + type);
712 case EVENT_POLL_STATE_OPERATOR: {
713 String opNames[] = (String[])ar.result;
715 if (opNames != null && opNames.length >= 3) {
716 mNewSS.setOperatorName (opNames[0], opNames[1], opNames[2]);
721 case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: {
722 ints = (int[])ar.result;
723 mNewSS.setIsManualSelection(ints[0] == 1);
728 } catch (RuntimeException ex) {
729 loge("Exception while polling service state. Probably malformed RIL response." + ex);
732 mPollingContext[0]--;
734 if (mPollingContext[0] == 0) {
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.
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.
745 * The test for the operators is to handle special roaming
746 * agreements and MVNO's.
748 boolean roaming = (mGsmRoaming || mDataRoaming);
749 if ((mGsmRoaming && isSameNamedOperators(mNewSS))
750 || isOperatorConsideredNonRoaming(mNewSS)) {
753 mNewSS.setRoaming(roaming);
754 mNewSS.setEmergencyOnly(mEmergencyOnly);
759 private void setSignalStrengthDefaultValues() {
760 mSignalStrength = new SignalStrength(true);
764 * A complete "service state" from our perspective is
765 * composed of a handful of separate requests to the radio.
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
771 private void pollState() {
772 mPollingContext = new int[1];
773 mPollingContext[0] = 0;
775 switch (mCi.getRadioState()) {
776 case RADIO_UNAVAILABLE:
777 mNewSS.setStateOutOfService();
778 mNewCellLoc.setStateInvalid();
779 setSignalStrengthDefaultValues();
780 mGotCountryCode = false;
781 mNitzUpdatedTime = false;
786 mNewSS.setStateOff();
787 mNewCellLoc.setStateInvalid();
788 setSignalStrengthDefaultValues();
789 mGotCountryCode = false;
790 mNitzUpdatedTime = false;
795 // Issue all poll-related commands at once
796 // then count down the responses, which
797 // are allowed to arrive out-of-order
799 mPollingContext[0]++;
802 EVENT_POLL_STATE_OPERATOR, mPollingContext));
804 mPollingContext[0]++;
805 mCi.getDataRegistrationState(
807 EVENT_POLL_STATE_GPRS, mPollingContext));
809 mPollingContext[0]++;
810 mCi.getVoiceRegistrationState(
812 EVENT_POLL_STATE_REGISTRATION, mPollingContext));
814 mPollingContext[0]++;
815 mCi.getNetworkSelectionMode(
817 EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));
822 private void pollStateDone() {
824 log("Poll ServiceState done: " +
825 " oldSS=[" + mSS + "] newSS=[" + mNewSS + "]" +
826 " oldMaxDataCalls=" + mMaxDataCalls +
827 " mNewMaxDataCalls=" + mNewMaxDataCalls +
828 " oldReasonDataDenied=" + mReasonDataDenied +
829 " mNewReasonDataDenied=" + mNewReasonDataDenied);
832 if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
833 mNewSS.setRoaming(true);
836 useDataRegStateForDataOnlyDevices();
838 boolean hasRegistered =
839 mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
840 && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
842 boolean hasDeregistered =
843 mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
844 && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
846 boolean hasGprsAttached =
847 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
848 && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
850 boolean hasGprsDetached =
851 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
852 && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
854 boolean hasDataRegStateChanged =
855 mSS.getDataRegState() != mNewSS.getDataRegState();
857 boolean hasVoiceRegStateChanged =
858 mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
860 boolean hasRilVoiceRadioTechnologyChanged =
861 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
863 boolean hasRilDataRadioTechnologyChanged =
864 mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
866 boolean hasChanged = !mNewSS.equals(mSS);
868 boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
870 boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
872 boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
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());
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) {
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());
897 + ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology())
899 + ServiceState.rilRadioTechnologyToString(
900 mNewSS.getRilVoiceRadioTechnology()) + " at cell " + cid);
904 // swap mSS and mNewSS to put new state in mSS
905 ServiceState tss = mSS;
908 // clean slate for next time
909 mNewSS.setStateOutOfService();
911 // swap mCellLoc and mNewCellLoc to put new state in mCellLoc
912 GsmCellLocation tcl = mCellLoc;
913 mCellLoc = mNewCellLoc;
916 mReasonDataDenied = mNewReasonDataDenied;
917 mMaxDataCalls = mNewMaxDataCalls;
919 if (hasRilVoiceRadioTechnologyChanged) {
923 if (hasRilDataRadioTechnologyChanged) {
924 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
925 ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology()));
929 mNetworkAttachedRegistrants.notifyRegistrants();
932 log("pollStateDone: registering current mNitzUpdatedTime=" +
933 mNitzUpdatedTime + " changing to false");
935 mNitzUpdatedTime = false;
939 String operatorNumeric;
943 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
944 mSS.getOperatorAlphaLong());
946 String prevOperatorNumeric =
947 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
948 operatorNumeric = mSS.getOperatorNumeric();
949 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
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;
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);
968 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso);
969 mGotCountryCode = true;
971 TimeZone zone = null;
973 if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) &&
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);
981 ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso);
982 if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) {
983 zone = uniqueZones.get(0);
985 log("pollStateDone: no nitz but one TZ for iso-cc=" + iso +
986 " with zone.getID=" + zone.getID() +
987 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
989 setAndBroadcastNetworkSetTimeZone(zone.getID());
992 log("pollStateDone: there are " + uniqueZones.size() +
993 " unique offsets for iso-cc='" + iso +
994 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath +
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
1005 String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
1007 log("pollStateDone: fix time zone zoneName='" + zoneName +
1008 "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
1010 "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso));
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);
1029 log("pollStateDone: tzOffset=" + tzOffset + " ltod=" +
1030 TimeUtils.logTimeOfDay(ctm));
1032 if (getAutoTime()) {
1033 long adj = ctm - tzOffset;
1034 if (DBG) log("pollStateDone: adj ltod=" +
1035 TimeUtils.logTimeOfDay(adj));
1036 setAndBroadcastNetworkSetTime(adj);
1038 // Adjust the saved NITZ time to account for tzOffset.
1039 mSavedTime = mSavedTime - tzOffset;
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");
1049 zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, iso);
1050 if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)");
1053 mNeedFixZoneAfterNitz = false;
1056 log("pollStateDone: zone != null zone.getID=" + zone.getID());
1057 if (getAutoTimeZone()) {
1058 setAndBroadcastNetworkSetTimeZone(zone.getID());
1060 saveNitzTimeZone(zone.getID());
1062 log("pollStateDone: zone == null");
1067 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
1068 mSS.getRoaming() ? "true" : "false");
1070 mPhone.notifyServiceStateChanged(mSS);
1073 if (hasGprsAttached) {
1074 mAttachedRegistrants.notifyRegistrants();
1077 if (hasGprsDetached) {
1078 mDetachedRegistrants.notifyRegistrants();
1081 if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
1082 notifyDataRegStateRilRadioTechnologyChanged();
1083 mPhone.notifyDataConnection(null);
1087 mRoamingOnRegistrants.notifyRegistrants();
1090 if (hasRoamingOff) {
1091 mRoamingOffRegistrants.notifyRegistrants();
1094 if (hasLocationChanged) {
1095 mPhone.notifyLocationChanged();
1098 if (! isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
1099 if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
1100 mStartedGprsRegCheck = true;
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),
1110 mReportedGprsNoReg = false;
1112 // TODO: Add GsmCellIdenity updating, see CdmaLteServiceStateTracker.
1116 * Check if GPRS got registered while voice is registered.
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
1122 private boolean isGprsConsistent(int dataRegState, int voiceRegState) {
1123 return !((voiceRegState == ServiceState.STATE_IN_SERVICE) &&
1124 (dataRegState != ServiceState.STATE_IN_SERVICE));
1128 * Returns a TimeZone object based only on parameters from the NITZ string.
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);
1136 if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID()));
1140 private TimeZone findTimeZone(int offset, boolean dst, long when) {
1141 int rawOffset = offset;
1143 rawOffset -= 3600000;
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) {
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
1169 msg = obtainMessage();
1170 msg.what = EVENT_POLL_SIGNAL_STRENGTH;
1174 // TODO Don't poll signal strength if screen is off
1175 sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
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.
1183 * @param ar an int value of RIL_RESTRICTED_STATE_*
1185 private void onRestrictedStateChanged(AsyncResult ar) {
1186 RestrictedState newRs = new RestrictedState();
1188 if (DBG) log("onRestrictedStateChanged: E rs "+ mRestrictedState);
1190 if (ar.exception == null) {
1191 int[] ints = (int[])ar.result;
1192 int state = ints[0];
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);
1206 if (DBG) log("onRestrictedStateChanged: new rs "+ newRs);
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);
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.
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);
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);
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);
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);
1269 mRestrictedState = newRs;
1271 log("onRestrictedStateChanged: X rs "+ mRestrictedState);
1274 /** code is registration state 0-5 from TS 27.007 7.2 */
1275 private int regCodeToServiceState(int code) {
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;
1288 return ServiceState.STATE_IN_SERVICE;
1292 return ServiceState.STATE_IN_SERVICE;
1295 loge("regCodeToServiceState: unexpected service state " + code);
1296 return ServiceState.STATE_OUT_OF_SERVICE;
1302 * code is registration state 0-5 from TS 27.007 7.2
1303 * returns true if registered roam, false otherwise
1305 private boolean regCodeIsRoaming (int code) {
1306 return ServiceState.RIL_REG_STATE_ROAMING == code;
1310 * Set roaming state if operator mcc is the same as sim mcc
1311 * and ons is different from spn
1313 * @param s ServiceState hold current ons
1314 * @return true if same operator
1316 private boolean isSameNamedOperators(ServiceState s) {
1317 String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty");
1319 String onsl = s.getOperatorAlphaLong();
1320 String onss = s.getOperatorAlphaShort();
1322 boolean equalsOnsl = onsl != null && spn.equals(onsl);
1323 boolean equalsOnss = onss != null && spn.equals(onss);
1325 return currentMccEqualsSimMcc(s) && (equalsOnsl || equalsOnss);
1329 * Compare SIM MCC with Operator MCC
1331 * @param s ServiceState hold current ons
1332 * @return true if both are same
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;
1341 equalsMcc = simNumeric.substring(0, 3).
1342 equals(operatorNumeric.substring(0, 3));
1343 } catch (Exception e){
1349 * Do not set roaming state in case of oprators considered non-roaming.
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.
1355 * @param s ServiceState hold current ons
1356 * @return false for roaming state set
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);
1363 if (numericArray.length == 0 || operatorNumeric == null)
1366 for (String numeric : numericArray) {
1367 if (operatorNumeric.startsWith(numeric))
1376 * @return The current GPRS state. IN_SERVICE is the same as "attached"
1377 * and OUT_OF_SERVICE is the same as detached.
1380 public int getCurrentDataConnectionState() {
1381 return mSS.getDataRegState();
1385 * @return true if phone is camping on a technology (eg UMTS)
1386 * that could support voice and data simultaneously.
1389 public boolean isConcurrentVoiceAndDataAllowed() {
1390 return (mSS.getRilVoiceRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
1394 * @return the current cell location information. Prefer Gsm location
1395 * information if available otherwise return LTE location information
1397 public CellLocation getCellLocation() {
1398 if ((mCellLoc.getLac() >= 0) && (mCellLoc.getCid() >= 0)) {
1399 if (DBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc);
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.
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
1412 // The tunnel'd LTE information is returned as follows:
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);
1445 log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther);
1451 log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther);
1453 return cellLocOther;
1456 log("getCellLocation(): X empty mCellLoc and CellInfo mCellLoc=" + mCellLoc);
1464 * nitzReceiveTime is time_t that the NITZ time was posted
1466 private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {
1467 // "yy/mm/dd,hh:mm:ss(+/-)tz"
1468 // tz is in number of quarter-hours
1470 long start = SystemClock.elapsedRealtime();
1471 if (DBG) {log("NITZ: " + nitz + "," + nitzReceiveTime +
1472 " start=" + start + " delay=" + (start - nitzReceiveTime));
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"));
1481 c.set(Calendar.DST_OFFSET, 0);
1483 String[] nitzSubs = nitz.split("[/:,+-]");
1485 int year = 2000 + Integer.parseInt(nitzSubs[0]);
1486 c.set(Calendar.YEAR, year);
1488 // month is 0 based!
1489 int month = Integer.parseInt(nitzSubs[1]) - 1;
1490 c.set(Calendar.MONTH, month);
1492 int date = Integer.parseInt(nitzSubs[2]);
1493 c.set(Calendar.DATE, date);
1495 int hour = Integer.parseInt(nitzSubs[3]);
1496 c.set(Calendar.HOUR, hour);
1498 int minute = Integer.parseInt(nitzSubs[4]);
1499 c.set(Calendar.MINUTE, minute);
1501 int second = Integer.parseInt(nitzSubs[5]);
1502 c.set(Calendar.SECOND, second);
1504 boolean sign = (nitz.indexOf('-') == -1);
1506 int tzOffset = Integer.parseInt(nitzSubs[6]);
1508 int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
1511 // The zone offset received from NITZ is for current local time,
1512 // so DST correction is already applied. Don't add it again.
1514 // tzOffset += dst * 4;
1516 // We could unapply it if we wanted the raw offset.
1518 tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
1520 TimeZone zone = null;
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 );
1531 String iso = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
1535 if (mGotCountryCode) {
1536 if (iso != null && iso.length() > 0) {
1537 zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
1538 c.getTimeInMillis(),
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());
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.
1555 mNeedFixZoneAfterNitz = true;
1556 mZoneOffset = tzOffset;
1557 mZoneDst = dst != 0;
1558 mZoneTime = c.getTimeInMillis();
1562 if (getAutoTimeZone()) {
1563 setAndBroadcastNetworkSetTimeZone(zone.getID());
1565 saveNitzTimeZone(zone.getID());
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");
1575 mWakeLock.acquire();
1577 if (getAutoTime()) {
1578 long millisSinceNitzReceived
1579 = SystemClock.elapsedRealtime() - nitzReceiveTime;
1581 if (millisSinceNitzReceived < 0) {
1582 // Sanity check: something is wrong
1584 log("NITZ: not setting time, clock has rolled "
1585 + "backwards since NITZ time was received, "
1591 if (millisSinceNitzReceived > Integer.MAX_VALUE) {
1592 // If the time is this far off, something is wrong > 24 days!
1594 log("NITZ: not setting time, processing has taken "
1595 + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
1601 // Note: with range checks above, cast to int is safe
1602 c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
1605 log("NITZ: Setting time of day to " + c.getTime()
1606 + " NITZ receive delay(ms): " + millisSinceNitzReceived
1608 + (c.getTimeInMillis() - System.currentTimeMillis())
1612 setAndBroadcastNetworkSetTime(c.getTimeInMillis());
1613 Rlog.i(LOG_TAG, "NITZ: after Setting time of day");
1615 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
1616 saveNitzTime(c.getTimeInMillis());
1618 long end = SystemClock.elapsedRealtime();
1619 log("NITZ: end=" + end + " dur=" + (end - start));
1621 mNitzUpdatedTime = true;
1623 mWakeLock.release();
1625 } catch (RuntimeException ex) {
1626 loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
1630 private boolean getAutoTime() {
1632 return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1633 Settings.Global.AUTO_TIME) > 0;
1634 } catch (SettingNotFoundException snfe) {
1639 private boolean getAutoTimeZone() {
1641 return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1642 Settings.Global.AUTO_TIME_ZONE) > 0;
1643 } catch (SettingNotFoundException snfe) {
1648 private void saveNitzTimeZone(String zoneId) {
1649 mSavedTimeZone = zoneId;
1652 private void saveNitzTime(long time) {
1654 mSavedAtTime = SystemClock.elapsedRealtime();
1658 * Set the timezone and send out a sticky broadcast so the system can
1659 * determine if the timezone was set by the carrier.
1661 * @param zoneId timezone set by carrier
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);
1673 log("setAndBroadcastNetworkSetTimeZone: call alarm.setTimeZone and broadcast zoneId=" +
1679 * Set the time and Send out a sticky broadcast so the system can determine
1680 * if the time was set by the carrier.
1682 * @param time time set by network
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);
1693 private void revertToNitzTime() {
1694 if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1695 Settings.Global.AUTO_TIME, 0) == 0) {
1699 log("Reverting to NITZ Time: mSavedTime=" + mSavedTime
1700 + " mSavedAtTime=" + mSavedAtTime);
1702 if (mSavedTime != 0 && mSavedAtTime != 0) {
1703 setAndBroadcastNetworkSetTime(mSavedTime
1704 + (SystemClock.elapsedRealtime() - mSavedAtTime));
1708 private void revertToNitzTimeZone() {
1709 if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1710 Settings.Global.AUTO_TIME_ZONE, 0) == 0) {
1713 if (DBG) log("Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);
1714 if (mSavedTimeZone != null) {
1715 setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
1720 * Post a notification to NotificationManager for restricted state
1722 * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE
1724 private void setNotification(int notifyType) {
1726 if (DBG) log("setNotification: create notification " + notifyType);
1727 Context context = mPhone.getContext();
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);
1737 CharSequence details = "";
1738 CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle);
1739 int notificationId = CS_NOTIFICATION;
1741 switch (notifyType) {
1743 notificationId = PS_NOTIFICATION;
1744 details = context.getText(com.android.internal.R.string.RestrictedOnData);
1747 notificationId = PS_NOTIFICATION;
1750 details = context.getText(com.android.internal.R.string.RestrictedOnAllVoice);
1752 case CS_NORMAL_ENABLED:
1753 details = context.getText(com.android.internal.R.string.RestrictedOnNormal);
1755 case CS_EMERGENCY_ENABLED:
1756 details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);
1759 // do nothing and cancel the notification later
1763 if (DBG) log("setNotification: put notification " + title + " / " +details);
1764 mNotification.tickerText = title;
1765 mNotification.setLatestEventInfo(context, title, details,
1766 mNotification.contentIntent);
1768 NotificationManager notificationManager = (NotificationManager)
1769 context.getSystemService(Context.NOTIFICATION_SERVICE);
1771 if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) {
1772 // cancel previous post notification
1773 notificationManager.cancel(notificationId);
1775 // update restricted state notification
1776 notificationManager.notify(notificationId, mNotification);
1781 protected void onUpdateIccAvailability() {
1782 if (mUiccController == null ) {
1786 UiccCardApplication newUiccApplication =
1787 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);
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);
1797 mUiccApplcation = null;
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);
1811 protected void log(String s) {
1812 Rlog.d(LOG_TAG, "[GsmSST] " + s);
1816 protected void loge(String s) {
1817 Rlog.e(LOG_TAG, "[GsmSST] " + s);
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);