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