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