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