GsmServiceStateTracker.java revision 88f9756a023639f48e85680b8bf2cd1469a5471a
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.IccRecords; 27import com.android.internal.telephony.MccTable; 28import com.android.internal.telephony.Phone; 29import com.android.internal.telephony.RestrictedState; 30import com.android.internal.telephony.RILConstants; 31import com.android.internal.telephony.ServiceStateTracker; 32import com.android.internal.telephony.TelephonyIntents; 33import com.android.internal.telephony.TelephonyProperties; 34import com.android.internal.telephony.UiccCard; 35import com.android.internal.telephony.UiccCardApplication; 36import com.android.internal.telephony.IccCardApplicationStatus.AppState; 37import com.android.internal.telephony.uicc.UiccController; 38 39import android.app.AlarmManager; 40import android.app.Notification; 41import android.app.NotificationManager; 42import android.app.PendingIntent; 43import android.content.BroadcastReceiver; 44import android.content.ContentResolver; 45import android.content.Context; 46import android.content.Intent; 47import android.content.IntentFilter; 48import android.content.res.Resources; 49import android.database.ContentObserver; 50import android.os.AsyncResult; 51import android.os.Handler; 52import android.os.Message; 53import android.os.PowerManager; 54import android.os.Registrant; 55import android.os.RegistrantList; 56import android.os.SystemClock; 57import android.os.SystemProperties; 58import android.os.UserHandle; 59import android.provider.Settings; 60import android.provider.Settings.SettingNotFoundException; 61import android.telephony.CellInfo; 62import android.telephony.CellInfoGsm; 63import android.telephony.ServiceState; 64import android.telephony.SignalStrength; 65import android.telephony.gsm.GsmCellLocation; 66import android.text.TextUtils; 67import android.util.EventLog; 68import android.util.Log; 69import android.util.TimeUtils; 70 71import java.io.FileDescriptor; 72import java.io.PrintWriter; 73import java.util.ArrayList; 74import java.util.Arrays; 75import java.util.Calendar; 76import java.util.Collection; 77import java.util.Date; 78import java.util.HashSet; 79import java.util.TimeZone; 80 81/** 82 * {@hide} 83 */ 84final class GsmServiceStateTracker extends ServiceStateTracker { 85 static final String LOG_TAG = "GSM"; 86 static final boolean DBG = true; 87 88 GSMPhone phone; 89 GsmCellLocation cellLoc; 90 GsmCellLocation newCellLoc; 91 int mPreferredNetworkType; 92 93 private int mMaxDataCalls = 1; 94 private int mNewMaxDataCalls = 1; 95 private int mReasonDataDenied = -1; 96 private int mNewReasonDataDenied = -1; 97 98 /** 99 * GSM roaming status solely based on TS 27.007 7.2 CREG. Only used by 100 * handlePollStateResult to store CREG roaming result. 101 */ 102 private boolean mGsmRoaming = false; 103 104 /** 105 * Data roaming status solely based on TS 27.007 10.1.19 CGREG. Only used by 106 * handlePollStateResult to store CGREG roaming result. 107 */ 108 private boolean mDataRoaming = false; 109 110 /** 111 * Mark when service state is in emergency call only mode 112 */ 113 private boolean mEmergencyOnly = false; 114 115 /** 116 * Sometimes we get the NITZ time before we know what country we 117 * are in. Keep the time zone information from the NITZ string so 118 * we can fix the time zone once know the country. 119 */ 120 private boolean mNeedFixZoneAfterNitz = false; 121 private int mZoneOffset; 122 private boolean mZoneDst; 123 private long mZoneTime; 124 private boolean mGotCountryCode = false; 125 private ContentResolver cr; 126 127 /** Boolean is true is setTimeFromNITZString was called */ 128 private boolean mNitzUpdatedTime = false; 129 130 String mSavedTimeZone; 131 long mSavedTime; 132 long mSavedAtTime; 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 boolean curShowPlmn = false; 153 private boolean curShowSpn = false; 154 155 156 /** waiting period before recheck gprs and voice registration. */ 157 static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; 158 159 /** Notification type. */ 160 static final int PS_ENABLED = 1001; // Access Control blocks data service 161 static final int PS_DISABLED = 1002; // Access Control enables data service 162 static final int CS_ENABLED = 1003; // Access Control blocks all voice/sms service 163 static final int CS_DISABLED = 1004; // Access Control enables all voice/sms service 164 static final int CS_NORMAL_ENABLED = 1005; // Access Control blocks normal voice/sms service 165 static final int CS_EMERGENCY_ENABLED = 1006; // Access Control blocks emergency call service 166 167 /** Notification id. */ 168 static final int PS_NOTIFICATION = 888; // Id to update and cancel PS restricted 169 static final int CS_NOTIFICATION = 999; // Id to update and cancel CS restricted 170 171 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 172 @Override 173 public void onReceive(Context context, Intent intent) { 174 if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) { 175 // update emergency string whenever locale changed 176 updateSpnDisplay(); 177 } 178 } 179 }; 180 181 private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { 182 @Override 183 public void onChange(boolean selfChange) { 184 Log.i("GsmServiceStateTracker", "Auto time state changed"); 185 revertToNitzTime(); 186 } 187 }; 188 189 private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) { 190 @Override 191 public void onChange(boolean selfChange) { 192 Log.i("GsmServiceStateTracker", "Auto time zone state changed"); 193 revertToNitzTimeZone(); 194 } 195 }; 196 197 public GsmServiceStateTracker(GSMPhone phone) { 198 super(phone, phone.mCM, new CellInfoGsm()); 199 200 this.phone = phone; 201 cellLoc = new GsmCellLocation(); 202 newCellLoc = new GsmCellLocation(); 203 204 PowerManager powerManager = 205 (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE); 206 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); 207 208 cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); 209 cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); 210 211 cm.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null); 212 cm.setOnNITZTime(this, EVENT_NITZ_TIME, null); 213 cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null); 214 215 // system setting property AIRPLANE_MODE_ON is set in Settings. 216 int airplaneMode = Settings.Global.getInt( 217 phone.getContext().getContentResolver(), 218 Settings.Global.AIRPLANE_MODE_ON, 0); 219 mDesiredPowerState = ! (airplaneMode > 0); 220 221 cr = phone.getContext().getContentResolver(); 222 cr.registerContentObserver( 223 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true, 224 mAutoTimeObserver); 225 cr.registerContentObserver( 226 Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, 227 mAutoTimeZoneObserver); 228 229 setSignalStrengthDefaultValues(); 230 231 // Monitor locale change 232 IntentFilter filter = new IntentFilter(); 233 filter.addAction(Intent.ACTION_LOCALE_CHANGED); 234 phone.getContext().registerReceiver(mIntentReceiver, filter); 235 236 // Gsm doesn't support OTASP so its not needed 237 phone.notifyOtaspChanged(OTASP_NOT_NEEDED); 238 } 239 240 @Override 241 public void dispose() { 242 checkCorrectThread(); 243 // Unregister for all events. 244 cm.unregisterForAvailable(this); 245 cm.unregisterForRadioStateChanged(this); 246 cm.unregisterForVoiceNetworkStateChanged(this); 247 if (mUiccApplcation != null) {mUiccApplcation.unregisterForReady(this);} 248 if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);} 249 cm.unSetOnRestrictedStateChanged(this); 250 cm.unSetOnNITZTime(this); 251 cr.unregisterContentObserver(this.mAutoTimeObserver); 252 cr.unregisterContentObserver(this.mAutoTimeZoneObserver); 253 phone.getContext().unregisterReceiver(mIntentReceiver); 254 super.dispose(); 255 } 256 257 protected void finalize() { 258 if(DBG) log("finalize"); 259 } 260 261 @Override 262 protected Phone getPhone() { 263 return phone; 264 } 265 266 public void handleMessage (Message msg) { 267 AsyncResult ar; 268 int[] ints; 269 String[] strings; 270 Message message; 271 272 if (!phone.mIsTheCurrentActivePhone) { 273 Log.e(LOG_TAG, "Received message " + msg + 274 "[" + msg.what + "] while being destroyed. Ignoring."); 275 return; 276 } 277 switch (msg.what) { 278 case EVENT_RADIO_AVAILABLE: 279 //this is unnecessary 280 //setPowerStateToDesired(); 281 break; 282 283 case EVENT_SIM_READY: 284 // Set the network type, in case the radio does not restore it. 285 cm.setCurrentPreferredNetworkType(); 286 287 boolean skipRestoringSelection = phone.getContext().getResources().getBoolean( 288 com.android.internal.R.bool.skip_restoring_network_selection); 289 290 if (!skipRestoringSelection) { 291 // restore the previous network selection. 292 phone.restoreSavedNetworkSelection(null); 293 } 294 pollState(); 295 // Signal strength polling stops when radio is off 296 queueNextSignalStrengthPoll(); 297 break; 298 299 case EVENT_RADIO_STATE_CHANGED: 300 // This will do nothing in the radio not 301 // available case 302 setPowerStateToDesired(); 303 pollState(); 304 break; 305 306 case EVENT_NETWORK_STATE_CHANGED: 307 pollState(); 308 break; 309 310 case EVENT_GET_SIGNAL_STRENGTH: 311 // This callback is called when signal strength is polled 312 // all by itself 313 314 if (!(cm.getRadioState().isOn())) { 315 // Polling will continue when radio turns back on 316 return; 317 } 318 ar = (AsyncResult) msg.obj; 319 onSignalStrengthResult(ar, true); 320 queueNextSignalStrengthPoll(); 321 322 break; 323 324 case EVENT_GET_LOC_DONE: 325 ar = (AsyncResult) msg.obj; 326 327 if (ar.exception == null) { 328 String states[] = (String[])ar.result; 329 int lac = -1; 330 int cid = -1; 331 if (states.length >= 3) { 332 try { 333 if (states[1] != null && states[1].length() > 0) { 334 lac = Integer.parseInt(states[1], 16); 335 } 336 if (states[2] != null && states[2].length() > 0) { 337 cid = Integer.parseInt(states[2], 16); 338 } 339 } catch (NumberFormatException ex) { 340 Log.w(LOG_TAG, "error parsing location: " + ex); 341 } 342 } 343 cellLoc.setLacAndCid(lac, cid); 344 phone.notifyLocationChanged(); 345 } 346 347 // Release any temporary cell lock, which could have been 348 // acquired to allow a single-shot location update. 349 disableSingleLocationUpdate(); 350 break; 351 352 case EVENT_POLL_STATE_REGISTRATION: 353 case EVENT_POLL_STATE_GPRS: 354 case EVENT_POLL_STATE_OPERATOR: 355 case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: 356 ar = (AsyncResult) msg.obj; 357 358 handlePollStateResult(msg.what, ar); 359 break; 360 361 case EVENT_POLL_SIGNAL_STRENGTH: 362 // Just poll signal strength...not part of pollState() 363 364 cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH)); 365 break; 366 367 case EVENT_NITZ_TIME: 368 ar = (AsyncResult) msg.obj; 369 370 String nitzString = (String)((Object[])ar.result)[0]; 371 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue(); 372 373 setTimeFromNITZString(nitzString, nitzReceiveTime); 374 break; 375 376 case EVENT_SIGNAL_STRENGTH_UPDATE: 377 // This is a notification from 378 // CommandsInterface.setOnSignalStrengthUpdate 379 380 ar = (AsyncResult) msg.obj; 381 382 // The radio is telling us about signal strength changes 383 // we don't have to ask it 384 dontPollSignalStrength = true; 385 386 onSignalStrengthResult(ar, true); 387 break; 388 389 case EVENT_SIM_RECORDS_LOADED: 390 updateSpnDisplay(); 391 break; 392 393 case EVENT_LOCATION_UPDATES_ENABLED: 394 ar = (AsyncResult) msg.obj; 395 396 if (ar.exception == null) { 397 cm.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null)); 398 } 399 break; 400 401 case EVENT_SET_PREFERRED_NETWORK_TYPE: 402 ar = (AsyncResult) msg.obj; 403 // Don't care the result, only use for dereg network (COPS=2) 404 message = obtainMessage(EVENT_RESET_PREFERRED_NETWORK_TYPE, ar.userObj); 405 cm.setPreferredNetworkType(mPreferredNetworkType, message); 406 break; 407 408 case EVENT_RESET_PREFERRED_NETWORK_TYPE: 409 ar = (AsyncResult) msg.obj; 410 if (ar.userObj != null) { 411 AsyncResult.forMessage(((Message) ar.userObj)).exception 412 = ar.exception; 413 ((Message) ar.userObj).sendToTarget(); 414 } 415 break; 416 417 case EVENT_GET_PREFERRED_NETWORK_TYPE: 418 ar = (AsyncResult) msg.obj; 419 420 if (ar.exception == null) { 421 mPreferredNetworkType = ((int[])ar.result)[0]; 422 } else { 423 mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL; 424 } 425 426 message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj); 427 int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL; 428 429 cm.setPreferredNetworkType(toggledNetworkType, message); 430 break; 431 432 case EVENT_CHECK_REPORT_GPRS: 433 if (ss != null && !isGprsConsistent(ss.getDataRegState(), ss.getVoiceState())) { 434 435 // Can't register data service while voice service is ok 436 // i.e. CREG is ok while CGREG is not 437 // possible a network or baseband side error 438 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); 439 EventLog.writeEvent(EventLogTags.DATA_NETWORK_REGISTRATION_FAIL, 440 ss.getOperatorNumeric(), loc != null ? loc.getCid() : -1); 441 mReportedGprsNoReg = true; 442 } 443 mStartedGprsRegCheck = false; 444 break; 445 446 case EVENT_RESTRICTED_STATE_CHANGED: 447 // This is a notification from 448 // CommandsInterface.setOnRestrictedStateChanged 449 450 if (DBG) log("EVENT_RESTRICTED_STATE_CHANGED"); 451 452 ar = (AsyncResult) msg.obj; 453 454 onRestrictedStateChanged(ar); 455 break; 456 457 default: 458 super.handleMessage(msg); 459 break; 460 } 461 } 462 463 protected void setPowerStateToDesired() { 464 // If we want it on and it's off, turn it on 465 if (mDesiredPowerState 466 && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { 467 cm.setRadioPower(true, null); 468 } else if (!mDesiredPowerState && cm.getRadioState().isOn()) { 469 // If it's on and available and we want it off gracefully 470 DataConnectionTracker dcTracker = phone.mDataConnectionTracker; 471 powerOffRadioSafely(dcTracker); 472 } // Otherwise, we're in the desired state 473 } 474 475 @Override 476 protected void hangupAndPowerOff() { 477 // hang up all active voice calls 478 if (phone.isInCall()) { 479 phone.mCT.ringingCall.hangupIfAlive(); 480 phone.mCT.backgroundCall.hangupIfAlive(); 481 phone.mCT.foregroundCall.hangupIfAlive(); 482 } 483 484 cm.setRadioPower(false, null); 485 } 486 487 @Override 488 protected void updateSpnDisplay() { 489 // The values of plmn/showPlmn change in different scenarios. 490 // 1) No service but emergency call allowed -> expected 491 // to show "Emergency call only" 492 // EXTRA_SHOW_PLMN = true 493 // EXTRA_PLMN = "Emergency call only" 494 495 // 2) No service at all --> expected to show "No service" 496 // EXTRA_SHOW_PLMN = true 497 // EXTRA_PLMN = "No service" 498 499 // 3) Normal operation in either home or roaming service 500 // EXTRA_SHOW_PLMN = depending on IccRecords rule 501 // EXTRA_PLMN = plmn 502 503 // 4) No service due to power off, aka airplane mode 504 // EXTRA_SHOW_PLMN = false 505 // EXTRA_PLMN = null 506 507 IccRecords iccRecords = mIccRecords; 508 String plmn = null; 509 boolean showPlmn = false; 510 int rule = (iccRecords != null) ? iccRecords.getDisplayRule(ss.getOperatorNumeric()) : 0; 511 if (ss.getVoiceState() == ServiceState.STATE_OUT_OF_SERVICE 512 || ss.getVoiceState() == ServiceState.STATE_EMERGENCY_ONLY) { 513 showPlmn = true; 514 if (mEmergencyOnly) { 515 // No service but emergency call allowed 516 plmn = Resources.getSystem(). 517 getText(com.android.internal.R.string.emergency_calls_only).toString(); 518 } else { 519 // No service at all 520 plmn = Resources.getSystem(). 521 getText(com.android.internal.R.string.lockscreen_carrier_default).toString(); 522 } 523 if (DBG) log("updateSpnDisplay: radio is on but out " + 524 "of service, set plmn='" + plmn + "'"); 525 } else if (ss.getVoiceState() == ServiceState.STATE_IN_SERVICE) { 526 // In either home or roaming service 527 plmn = ss.getOperatorAlphaLong(); 528 showPlmn = !TextUtils.isEmpty(plmn) && 529 ((rule & SIMRecords.SPN_RULE_SHOW_PLMN) 530 == SIMRecords.SPN_RULE_SHOW_PLMN); 531 } else { 532 // Power off state, such as airplane mode 533 if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn=" 534 + showPlmn + " plmn=" + plmn); 535 } 536 537 // The value of spn/showSpn are same in different scenarios. 538 // EXTRA_SHOW_SPN = depending on IccRecords rule 539 // EXTRA_SPN = spn 540 String spn = (iccRecords != null) ? iccRecords.getServiceProviderName() : ""; 541 boolean showSpn = !TextUtils.isEmpty(spn) 542 && ((rule & SIMRecords.SPN_RULE_SHOW_SPN) 543 == SIMRecords.SPN_RULE_SHOW_SPN); 544 545 // Update SPN_STRINGS_UPDATED_ACTION IFF any value changes 546 if (showPlmn != curShowPlmn 547 || showSpn != curShowSpn 548 || !TextUtils.equals(spn, curSpn) 549 || !TextUtils.equals(plmn, curPlmn)) { 550 if (DBG) { 551 log(String.format("updateSpnDisplay: changed" + 552 " sending intent rule=" + rule + 553 " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s'", 554 showPlmn, plmn, showSpn, spn)); 555 } 556 Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); 557 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 558 intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn); 559 intent.putExtra(TelephonyIntents.EXTRA_SPN, spn); 560 intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn); 561 intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn); 562 phone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 563 } 564 565 curShowSpn = showSpn; 566 curShowPlmn = showPlmn; 567 curSpn = spn; 568 curPlmn = plmn; 569 } 570 571 /** 572 * Handle the result of one of the pollState()-related requests 573 */ 574 @Override 575 protected void handlePollStateResult (int what, AsyncResult ar) { 576 int ints[]; 577 String states[]; 578 579 // Ignore stale requests from last poll 580 if (ar.userObj != pollingContext) return; 581 582 if (ar.exception != null) { 583 CommandException.Error err=null; 584 585 if (ar.exception instanceof CommandException) { 586 err = ((CommandException)(ar.exception)).getCommandError(); 587 } 588 589 if (err == CommandException.Error.RADIO_NOT_AVAILABLE) { 590 // Radio has crashed or turned off 591 cancelPollState(); 592 return; 593 } 594 595 if (!cm.getRadioState().isOn()) { 596 // Radio has crashed or turned off 597 cancelPollState(); 598 return; 599 } 600 601 if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) { 602 loge("RIL implementation has returned an error where it must succeed" + 603 ar.exception); 604 } 605 } else try { 606 switch (what) { 607 case EVENT_POLL_STATE_REGISTRATION: { 608 states = (String[])ar.result; 609 int lac = -1; 610 int cid = -1; 611 int type = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; 612 int regState = ServiceState.RIL_REG_STATE_UNKNOWN; 613 int reasonRegStateDenied = -1; 614 int psc = -1; 615 if (states.length > 0) { 616 try { 617 regState = Integer.parseInt(states[0]); 618 if (states.length >= 3) { 619 if (states[1] != null && states[1].length() > 0) { 620 lac = Integer.parseInt(states[1], 16); 621 } 622 if (states[2] != null && states[2].length() > 0) { 623 cid = Integer.parseInt(states[2], 16); 624 } 625 626 // states[3] (if present) is the current radio technology 627 if (states.length >= 4 && states[3] != null) { 628 type = Integer.parseInt(states[3]); 629 } 630 } 631 if (states.length > 14) { 632 if (states[14] != null && states[14].length() > 0) { 633 psc = Integer.parseInt(states[14], 16); 634 } 635 } 636 } catch (NumberFormatException ex) { 637 loge("error parsing RegistrationState: " + ex); 638 } 639 } 640 641 mGsmRoaming = regCodeIsRoaming(regState); 642 newSS.setState(regCodeToServiceState(regState)); 643 newSS.setRilVoiceRadioTechnology(type); 644 645 if (regState == ServiceState.RIL_REG_STATE_DENIED_EMERGENCY_CALL_ENABLED 646 || regState == ServiceState.RIL_REG_STATE_NOT_REG_EMERGENCY_CALL_ENABLED 647 || regState == ServiceState.RIL_REG_STATE_SEARCHING_EMERGENCY_CALL_ENABLED 648 || regState == ServiceState.RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED) { 649 mEmergencyOnly = true; 650 } else { 651 mEmergencyOnly = false; 652 } 653 654 // LAC and CID are -1 if not avail 655 newCellLoc.setLacAndCid(lac, cid); 656 newCellLoc.setPsc(psc); 657 break; 658 } 659 660 case EVENT_POLL_STATE_GPRS: { 661 states = (String[])ar.result; 662 663 int type = 0; 664 int regState = ServiceState.RIL_REG_STATE_UNKNOWN; 665 mNewReasonDataDenied = -1; 666 mNewMaxDataCalls = 1; 667 if (states.length > 0) { 668 try { 669 regState = Integer.parseInt(states[0]); 670 671 // states[3] (if present) is the current radio technology 672 if (states.length >= 4 && states[3] != null) { 673 type = Integer.parseInt(states[3]); 674 } 675 if ((states.length >= 5 ) && 676 (regState == ServiceState.RIL_REG_STATE_DENIED)) { 677 mNewReasonDataDenied = Integer.parseInt(states[4]); 678 } 679 if (states.length >= 6) { 680 mNewMaxDataCalls = Integer.parseInt(states[5]); 681 } 682 } catch (NumberFormatException ex) { 683 loge("error parsing GprsRegistrationState: " + ex); 684 } 685 } 686 int dataRegState = regCodeToServiceState(regState); 687 newSS.setDataRegState(dataRegState); 688 mDataRoaming = regCodeIsRoaming(regState); 689 newSS.setRilDataRadioTechnology(type); 690 if (DBG) { 691 log("handlPollStateResultMessage: GsmSST setDataRegState=" + dataRegState 692 + " regState=" + regState 693 + " dataRadioTechnology=" + type); 694 } 695 break; 696 } 697 698 case EVENT_POLL_STATE_OPERATOR: { 699 String opNames[] = (String[])ar.result; 700 701 if (opNames != null && opNames.length >= 3) { 702 newSS.setOperatorName (opNames[0], opNames[1], opNames[2]); 703 } 704 break; 705 } 706 707 case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: { 708 ints = (int[])ar.result; 709 newSS.setIsManualSelection(ints[0] == 1); 710 break; 711 } 712 } 713 714 } catch (RuntimeException ex) { 715 loge("Exception while polling service state. Probably malformed RIL response." + ex); 716 } 717 718 pollingContext[0]--; 719 720 if (pollingContext[0] == 0) { 721 /** 722 * Since the roaming states of gsm service (from +CREG) and 723 * data service (from +CGREG) could be different, the new SS 724 * is set roaming while either one is roaming. 725 * 726 * There is an exception for the above rule. The new SS is not set 727 * as roaming while gsm service reports roaming but indeed it is 728 * not roaming between operators. 729 */ 730 boolean roaming = (mGsmRoaming || mDataRoaming); 731 if (mGsmRoaming && !isRoamingBetweenOperators(mGsmRoaming, newSS)) { 732 roaming = false; 733 } 734 newSS.setRoaming(roaming); 735 newSS.setEmergencyOnly(mEmergencyOnly); 736 pollStateDone(); 737 } 738 } 739 740 private void setSignalStrengthDefaultValues() { 741 mSignalStrength = new SignalStrength(true); 742 } 743 744 /** 745 * A complete "service state" from our perspective is 746 * composed of a handful of separate requests to the radio. 747 * 748 * We make all of these requests at once, but then abandon them 749 * and start over again if the radio notifies us that some 750 * event has changed 751 */ 752 private void pollState() { 753 pollingContext = new int[1]; 754 pollingContext[0] = 0; 755 756 switch (cm.getRadioState()) { 757 case RADIO_UNAVAILABLE: 758 newSS.setStateOutOfService(); 759 newCellLoc.setStateInvalid(); 760 setSignalStrengthDefaultValues(); 761 mGotCountryCode = false; 762 mNitzUpdatedTime = false; 763 pollStateDone(); 764 break; 765 766 case RADIO_OFF: 767 newSS.setStateOff(); 768 newCellLoc.setStateInvalid(); 769 setSignalStrengthDefaultValues(); 770 mGotCountryCode = false; 771 mNitzUpdatedTime = false; 772 pollStateDone(); 773 break; 774 775 default: 776 // Issue all poll-related commands at once 777 // then count down the responses, which 778 // are allowed to arrive out-of-order 779 780 pollingContext[0]++; 781 cm.getOperator( 782 obtainMessage( 783 EVENT_POLL_STATE_OPERATOR, pollingContext)); 784 785 pollingContext[0]++; 786 cm.getDataRegistrationState( 787 obtainMessage( 788 EVENT_POLL_STATE_GPRS, pollingContext)); 789 790 pollingContext[0]++; 791 cm.getVoiceRegistrationState( 792 obtainMessage( 793 EVENT_POLL_STATE_REGISTRATION, pollingContext)); 794 795 pollingContext[0]++; 796 cm.getNetworkSelectionMode( 797 obtainMessage( 798 EVENT_POLL_STATE_NETWORK_SELECTION_MODE, pollingContext)); 799 break; 800 } 801 } 802 803 private void pollStateDone() { 804 if (DBG) { 805 log("Poll ServiceState done: " + 806 " oldSS=[" + ss + "] newSS=[" + newSS + "]" + 807 " oldMaxDataCalls=" + mMaxDataCalls + 808 " mNewMaxDataCalls=" + mNewMaxDataCalls + 809 " oldReasonDataDenied=" + mReasonDataDenied + 810 " mNewReasonDataDenied=" + mNewReasonDataDenied); 811 } 812 813 boolean hasRegistered = 814 ss.getVoiceState() != ServiceState.STATE_IN_SERVICE 815 && newSS.getVoiceState() == ServiceState.STATE_IN_SERVICE; 816 817 boolean hasDeregistered = 818 ss.getVoiceState() == ServiceState.STATE_IN_SERVICE 819 && newSS.getVoiceState() != ServiceState.STATE_IN_SERVICE; 820 821 boolean hasGprsAttached = 822 ss.getDataRegState() != ServiceState.STATE_IN_SERVICE 823 && newSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; 824 825 boolean hasGprsDetached = 826 ss.getDataRegState() == ServiceState.STATE_IN_SERVICE 827 && newSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; 828 829 boolean hasRilVoiceRadioTechnologyChanged = 830 ss.getRilVoiceRadioTechnology() != newSS.getRilVoiceRadioTechnology(); 831 832 boolean hasChanged = !newSS.equals(ss); 833 834 boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming(); 835 836 boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming(); 837 838 boolean hasLocationChanged = !newCellLoc.equals(cellLoc); 839 840 // Add an event log when connection state changes 841 if (ss.getVoiceState() != newSS.getVoiceState() 842 || ss.getDataRegState() != newSS.getDataRegState()) { 843 EventLog.writeEvent(EventLogTags.GSM_SERVICE_STATE_CHANGE, 844 ss.getVoiceState(), ss.getDataRegState(), 845 newSS.getVoiceState(), newSS.getDataRegState()); 846 } 847 848 ServiceState tss; 849 tss = ss; 850 ss = newSS; 851 newSS = tss; 852 // clean slate for next time 853 newSS.setStateOutOfService(); 854 855 GsmCellLocation tcl = cellLoc; 856 cellLoc = newCellLoc; 857 newCellLoc = tcl; 858 859 // Add an event log when network type switched 860 // TODO: we may add filtering to reduce the event logged, 861 // i.e. check preferred network setting, only switch to 2G, etc 862 if (hasRilVoiceRadioTechnologyChanged) { 863 int cid = -1; 864 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); 865 if (loc != null) cid = loc.getCid(); 866 EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED, cid, ss.getRilVoiceRadioTechnology(), 867 newSS.getRilVoiceRadioTechnology()); 868 if (DBG) { 869 log("RAT switched " 870 + ServiceState.rilRadioTechnologyToString(ss.getRilVoiceRadioTechnology()) 871 + " -> " 872 + ServiceState.rilRadioTechnologyToString(newSS.getRilVoiceRadioTechnology()) + 873 " at cell " + cid); 874 } 875 } 876 877 mReasonDataDenied = mNewReasonDataDenied; 878 mMaxDataCalls = mNewMaxDataCalls; 879 880 newSS.setStateOutOfService(); // clean slate for next time 881 882 if (hasRilVoiceRadioTechnologyChanged) { 883 phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 884 ServiceState.rilRadioTechnologyToString(ss.getRilVoiceRadioTechnology())); 885 } 886 887 if (hasRegistered) { 888 mNetworkAttachedRegistrants.notifyRegistrants(); 889 890 if (DBG) { 891 log("pollStateDone: registering current mNitzUpdatedTime=" + 892 mNitzUpdatedTime + " changing to false"); 893 } 894 mNitzUpdatedTime = false; 895 } 896 897 if (hasChanged) { 898 String operatorNumeric; 899 900 updateSpnDisplay(); 901 902 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 903 ss.getOperatorAlphaLong()); 904 905 String prevOperatorNumeric = 906 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); 907 operatorNumeric = ss.getOperatorNumeric(); 908 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 909 910 if (operatorNumeric == null) { 911 if (DBG) log("operatorNumeric is null"); 912 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 913 mGotCountryCode = false; 914 mNitzUpdatedTime = false; 915 } else { 916 String iso = ""; 917 String mcc = ""; 918 try{ 919 mcc = operatorNumeric.substring(0, 3); 920 iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc)); 921 } catch ( NumberFormatException ex){ 922 loge("pollStateDone: countryCodeForMcc error" + ex); 923 } catch ( StringIndexOutOfBoundsException ex) { 924 loge("pollStateDone: countryCodeForMcc error" + ex); 925 } 926 927 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso); 928 mGotCountryCode = true; 929 930 TimeZone zone = null; 931 932 if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) && 933 getAutoTimeZone()) { 934 935 // Test both paths if ignore nitz is true 936 boolean testOneUniqueOffsetPath = SystemProperties.getBoolean( 937 TelephonyProperties.PROPERTY_IGNORE_NITZ, false) && 938 ((SystemClock.uptimeMillis() & 1) == 0); 939 940 ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso); 941 if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) { 942 zone = uniqueZones.get(0); 943 if (DBG) { 944 log("pollStateDone: no nitz but one TZ for iso-cc=" + iso + 945 " with zone.getID=" + zone.getID() + 946 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath); 947 } 948 setAndBroadcastNetworkSetTimeZone(zone.getID()); 949 } else { 950 if (DBG) { 951 log("pollStateDone: there are " + uniqueZones.size() + 952 " unique offsets for iso-cc='" + iso + 953 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath + 954 "', do nothing"); 955 } 956 } 957 } 958 959 if (shouldFixTimeZoneNow(phone, operatorNumeric, prevOperatorNumeric, 960 mNeedFixZoneAfterNitz)) { 961 // If the offset is (0, false) and the timezone property 962 // is set, use the timezone property rather than 963 // GMT. 964 String zoneName = SystemProperties.get(TIMEZONE_PROPERTY); 965 if (DBG) { 966 log("pollStateDone: fix time zone zoneName='" + zoneName + 967 "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst + 968 " iso-cc='" + iso + 969 "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso)); 970 } 971 972 // "(mZoneOffset == 0) && (mZoneDst == false) && 973 // (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)" 974 // means that we received a NITZ string telling 975 // it is in GMT+0 w/ DST time zone 976 // BUT iso tells is NOT, e.g, a wrong NITZ reporting 977 // local time w/ 0 offset. 978 if ((mZoneOffset == 0) && (mZoneDst == false) && 979 (zoneName != null) && (zoneName.length() > 0) && 980 (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) { 981 zone = TimeZone.getDefault(); 982 if (mNeedFixZoneAfterNitz) { 983 // For wrong NITZ reporting local time w/ 0 offset, 984 // need adjust time to reflect default timezone setting 985 long ctm = System.currentTimeMillis(); 986 long tzOffset = zone.getOffset(ctm); 987 if (DBG) { 988 log("pollStateDone: tzOffset=" + tzOffset + " ltod=" + 989 TimeUtils.logTimeOfDay(ctm)); 990 } 991 if (getAutoTime()) { 992 long adj = ctm - tzOffset; 993 if (DBG) log("pollStateDone: adj ltod=" + 994 TimeUtils.logTimeOfDay(adj)); 995 setAndBroadcastNetworkSetTime(adj); 996 } else { 997 // Adjust the saved NITZ time to account for tzOffset. 998 mSavedTime = mSavedTime - tzOffset; 999 } 1000 } 1001 if (DBG) log("pollStateDone: using default TimeZone"); 1002 } else if (iso.equals("")){ 1003 // Country code not found. This is likely a test network. 1004 // Get a TimeZone based only on the NITZ parameters (best guess). 1005 zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime); 1006 if (DBG) log("pollStateDone: using NITZ TimeZone"); 1007 } else { 1008 zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, iso); 1009 if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)"); 1010 } 1011 1012 mNeedFixZoneAfterNitz = false; 1013 1014 if (zone != null) { 1015 log("pollStateDone: zone != null zone.getID=" + zone.getID()); 1016 if (getAutoTimeZone()) { 1017 setAndBroadcastNetworkSetTimeZone(zone.getID()); 1018 } 1019 saveNitzTimeZone(zone.getID()); 1020 } else { 1021 log("pollStateDone: zone == null"); 1022 } 1023 } 1024 } 1025 1026 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 1027 ss.getRoaming() ? "true" : "false"); 1028 1029 phone.notifyServiceStateChanged(ss); 1030 } 1031 1032 if (hasGprsAttached) { 1033 mAttachedRegistrants.notifyRegistrants(); 1034 } 1035 1036 if (hasGprsDetached) { 1037 mDetachedRegistrants.notifyRegistrants(); 1038 } 1039 1040 if (hasRilVoiceRadioTechnologyChanged) { 1041 phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED); 1042 } 1043 1044 if (hasRoamingOn) { 1045 mRoamingOnRegistrants.notifyRegistrants(); 1046 } 1047 1048 if (hasRoamingOff) { 1049 mRoamingOffRegistrants.notifyRegistrants(); 1050 } 1051 1052 if (hasLocationChanged) { 1053 phone.notifyLocationChanged(); 1054 } 1055 1056 if (! isGprsConsistent(ss.getDataRegState(), ss.getVoiceState())) { 1057 if (!mStartedGprsRegCheck && !mReportedGprsNoReg) { 1058 mStartedGprsRegCheck = true; 1059 1060 int check_period = Settings.Global.getInt( 1061 phone.getContext().getContentResolver(), 1062 Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS, 1063 DEFAULT_GPRS_CHECK_PERIOD_MILLIS); 1064 sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS), 1065 check_period); 1066 } 1067 } else { 1068 mReportedGprsNoReg = false; 1069 } 1070 // TODO: Add GsmCellIdenity updating, see CdmaLteServiceStateTracker. 1071 } 1072 1073 /** 1074 * Check if GPRS got registered while voice is registered. 1075 * 1076 * @param dataRegState, i.e. CGREG in GSM 1077 * @param voiceRegState, i.e. CREG in GSM 1078 * @return false if device only register to voice but not gprs 1079 */ 1080 private boolean isGprsConsistent(int dataRegState, int voiceRegState) { 1081 return !((voiceRegState == ServiceState.STATE_IN_SERVICE) && 1082 (dataRegState != ServiceState.STATE_IN_SERVICE)); 1083 } 1084 1085 /** 1086 * Returns a TimeZone object based only on parameters from the NITZ string. 1087 */ 1088 private TimeZone getNitzTimeZone(int offset, boolean dst, long when) { 1089 TimeZone guess = findTimeZone(offset, dst, when); 1090 if (guess == null) { 1091 // Couldn't find a proper timezone. Perhaps the DST data is wrong. 1092 guess = findTimeZone(offset, !dst, when); 1093 } 1094 if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID())); 1095 return guess; 1096 } 1097 1098 private TimeZone findTimeZone(int offset, boolean dst, long when) { 1099 int rawOffset = offset; 1100 if (dst) { 1101 rawOffset -= 3600000; 1102 } 1103 String[] zones = TimeZone.getAvailableIDs(rawOffset); 1104 TimeZone guess = null; 1105 Date d = new Date(when); 1106 for (String zone : zones) { 1107 TimeZone tz = TimeZone.getTimeZone(zone); 1108 if (tz.getOffset(when) == offset && 1109 tz.inDaylightTime(d) == dst) { 1110 guess = tz; 1111 break; 1112 } 1113 } 1114 1115 return guess; 1116 } 1117 1118 private void queueNextSignalStrengthPoll() { 1119 if (dontPollSignalStrength) { 1120 // The radio is telling us about signal strength changes 1121 // we don't have to ask it 1122 return; 1123 } 1124 1125 Message msg; 1126 1127 msg = obtainMessage(); 1128 msg.what = EVENT_POLL_SIGNAL_STRENGTH; 1129 1130 long nextTime; 1131 1132 // TODO Don't poll signal strength if screen is off 1133 sendMessageDelayed(msg, POLL_PERIOD_MILLIS); 1134 } 1135 1136 /** 1137 * Set restricted state based on the OnRestrictedStateChanged notification 1138 * If any voice or packet restricted state changes, trigger a UI 1139 * notification and notify registrants when sim is ready. 1140 * 1141 * @param ar an int value of RIL_RESTRICTED_STATE_* 1142 */ 1143 private void onRestrictedStateChanged(AsyncResult ar) { 1144 RestrictedState newRs = new RestrictedState(); 1145 1146 if (DBG) log("onRestrictedStateChanged: E rs "+ mRestrictedState); 1147 1148 if (ar.exception == null) { 1149 int[] ints = (int[])ar.result; 1150 int state = ints[0]; 1151 1152 newRs.setCsEmergencyRestricted( 1153 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) || 1154 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); 1155 //ignore the normal call and data restricted state before SIM READY 1156 if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY) { 1157 newRs.setCsNormalRestricted( 1158 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) || 1159 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); 1160 newRs.setPsRestricted( 1161 (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0); 1162 } 1163 1164 if (DBG) log("onRestrictedStateChanged: new rs "+ newRs); 1165 1166 if (!mRestrictedState.isPsRestricted() && newRs.isPsRestricted()) { 1167 mPsRestrictEnabledRegistrants.notifyRegistrants(); 1168 setNotification(PS_ENABLED); 1169 } else if (mRestrictedState.isPsRestricted() && !newRs.isPsRestricted()) { 1170 mPsRestrictDisabledRegistrants.notifyRegistrants(); 1171 setNotification(PS_DISABLED); 1172 } 1173 1174 /** 1175 * There are two kind of cs restriction, normal and emergency. So 1176 * there are 4 x 4 combinations in current and new restricted states 1177 * and we only need to notify when state is changed. 1178 */ 1179 if (mRestrictedState.isCsRestricted()) { 1180 if (!newRs.isCsRestricted()) { 1181 // remove all restriction 1182 setNotification(CS_DISABLED); 1183 } else if (!newRs.isCsNormalRestricted()) { 1184 // remove normal restriction 1185 setNotification(CS_EMERGENCY_ENABLED); 1186 } else if (!newRs.isCsEmergencyRestricted()) { 1187 // remove emergency restriction 1188 setNotification(CS_NORMAL_ENABLED); 1189 } 1190 } else if (mRestrictedState.isCsEmergencyRestricted() && 1191 !mRestrictedState.isCsNormalRestricted()) { 1192 if (!newRs.isCsRestricted()) { 1193 // remove all restriction 1194 setNotification(CS_DISABLED); 1195 } else if (newRs.isCsRestricted()) { 1196 // enable all restriction 1197 setNotification(CS_ENABLED); 1198 } else if (newRs.isCsNormalRestricted()) { 1199 // remove emergency restriction and enable normal restriction 1200 setNotification(CS_NORMAL_ENABLED); 1201 } 1202 } else if (!mRestrictedState.isCsEmergencyRestricted() && 1203 mRestrictedState.isCsNormalRestricted()) { 1204 if (!newRs.isCsRestricted()) { 1205 // remove all restriction 1206 setNotification(CS_DISABLED); 1207 } else if (newRs.isCsRestricted()) { 1208 // enable all restriction 1209 setNotification(CS_ENABLED); 1210 } else if (newRs.isCsEmergencyRestricted()) { 1211 // remove normal restriction and enable emergency restriction 1212 setNotification(CS_EMERGENCY_ENABLED); 1213 } 1214 } else { 1215 if (newRs.isCsRestricted()) { 1216 // enable all restriction 1217 setNotification(CS_ENABLED); 1218 } else if (newRs.isCsEmergencyRestricted()) { 1219 // enable emergency restriction 1220 setNotification(CS_EMERGENCY_ENABLED); 1221 } else if (newRs.isCsNormalRestricted()) { 1222 // enable normal restriction 1223 setNotification(CS_NORMAL_ENABLED); 1224 } 1225 } 1226 1227 mRestrictedState = newRs; 1228 } 1229 log("onRestrictedStateChanged: X rs "+ mRestrictedState); 1230 } 1231 1232 /** code is registration state 0-5 from TS 27.007 7.2 */ 1233 private int regCodeToServiceState(int code) { 1234 switch (code) { 1235 case 0: 1236 case 2: // 2 is "searching" 1237 case 3: // 3 is "registration denied" 1238 case 4: // 4 is "unknown" no vaild in current baseband 1239 case 10:// same as 0, but indicates that emergency call is possible. 1240 case 12:// same as 2, but indicates that emergency call is possible. 1241 case 13:// same as 3, but indicates that emergency call is possible. 1242 case 14:// same as 4, but indicates that emergency call is possible. 1243 return ServiceState.STATE_OUT_OF_SERVICE; 1244 1245 case 1: 1246 return ServiceState.STATE_IN_SERVICE; 1247 1248 case 5: 1249 // in service, roam 1250 return ServiceState.STATE_IN_SERVICE; 1251 1252 default: 1253 loge("regCodeToServiceState: unexpected service state " + code); 1254 return ServiceState.STATE_OUT_OF_SERVICE; 1255 } 1256 } 1257 1258 1259 /** 1260 * code is registration state 0-5 from TS 27.007 7.2 1261 * returns true if registered roam, false otherwise 1262 */ 1263 private boolean regCodeIsRoaming (int code) { 1264 return ServiceState.RIL_REG_STATE_ROAMING == code; 1265 } 1266 1267 /** 1268 * Set roaming state when gsmRoaming is true and, if operator mcc is the 1269 * same as sim mcc, ons is different from spn 1270 * @param gsmRoaming TS 27.007 7.2 CREG registered roaming 1271 * @param s ServiceState hold current ons 1272 * @return true for roaming state set 1273 */ 1274 private boolean isRoamingBetweenOperators(boolean gsmRoaming, ServiceState s) { 1275 String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty"); 1276 1277 String onsl = s.getOperatorAlphaLong(); 1278 String onss = s.getOperatorAlphaShort(); 1279 1280 boolean equalsOnsl = onsl != null && spn.equals(onsl); 1281 boolean equalsOnss = onss != null && spn.equals(onss); 1282 1283 String simNumeric = SystemProperties.get( 1284 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, ""); 1285 String operatorNumeric = s.getOperatorNumeric(); 1286 1287 boolean equalsMcc = true; 1288 try { 1289 equalsMcc = simNumeric.substring(0, 3). 1290 equals(operatorNumeric.substring(0, 3)); 1291 } catch (Exception e){ 1292 } 1293 1294 return gsmRoaming && !(equalsMcc && (equalsOnsl || equalsOnss)); 1295 } 1296 1297 private static int twoDigitsAt(String s, int offset) { 1298 int a, b; 1299 1300 a = Character.digit(s.charAt(offset), 10); 1301 b = Character.digit(s.charAt(offset+1), 10); 1302 1303 if (a < 0 || b < 0) { 1304 1305 throw new RuntimeException("invalid format"); 1306 } 1307 1308 return a*10 + b; 1309 } 1310 1311 /** 1312 * @return The current GPRS state. IN_SERVICE is the same as "attached" 1313 * and OUT_OF_SERVICE is the same as detached. 1314 */ 1315 @Override 1316 public int getCurrentDataConnectionState() { 1317 return ss.getDataRegState(); 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 (ss.getRilVoiceRadioTechnology() >= 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.Global.getInt(phone.getContext().getContentResolver(), 1531 Settings.Global.AUTO_TIME) > 0; 1532 } catch (SettingNotFoundException snfe) { 1533 return true; 1534 } 1535 } 1536 1537 private boolean getAutoTimeZone() { 1538 try { 1539 return Settings.Global.getInt(phone.getContext().getContentResolver(), 1540 Settings.Global.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().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 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().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1589 } 1590 1591 private void revertToNitzTime() { 1592 if (Settings.Global.getInt(phone.getContext().getContentResolver(), 1593 Settings.Global.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.Global.getInt(phone.getContext().getContentResolver(), 1608 Settings.Global.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 onUpdateIccAvailability() { 1680 if (mUiccController == null ) { 1681 return; 1682 } 1683 1684 UiccCardApplication newUiccApplication = 1685 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP); 1686 1687 if (mUiccApplcation != newUiccApplication) { 1688 if (mUiccApplcation != null) { 1689 log("Removing stale icc objects."); 1690 mUiccApplcation.unregisterForReady(this); 1691 if (mIccRecords != null) { 1692 mIccRecords.unregisterForRecordsLoaded(this); 1693 } 1694 mIccRecords = null; 1695 mUiccApplcation = null; 1696 } 1697 if (newUiccApplication != null) { 1698 log("New card found"); 1699 mUiccApplcation = newUiccApplication; 1700 mIccRecords = mUiccApplcation.getIccRecords(); 1701 mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null); 1702 if (mIccRecords != null) { 1703 mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); 1704 } 1705 } 1706 } 1707 } 1708 @Override 1709 protected void log(String s) { 1710 Log.d(LOG_TAG, "[GsmSST] " + s); 1711 } 1712 1713 @Override 1714 protected void loge(String s) { 1715 Log.e(LOG_TAG, "[GsmSST] " + s); 1716 } 1717 1718 private static void sloge(String s) { 1719 Log.e(LOG_TAG, "[GsmSST] " + s); 1720 } 1721 1722 @Override 1723 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1724 pw.println("GsmServiceStateTracker extends:"); 1725 super.dump(fd, pw, args); 1726 pw.println(" phone=" + phone); 1727 pw.println(" ss=" + ss); 1728 pw.println(" newSS=" + newSS); 1729 pw.println(" cellLoc=" + cellLoc); 1730 pw.println(" newCellLoc=" + newCellLoc); 1731 pw.println(" mPreferredNetworkType=" + mPreferredNetworkType); 1732 pw.println(" mMaxDataCalls=" + mMaxDataCalls); 1733 pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls); 1734 pw.println(" mReasonDataDenied=" + mReasonDataDenied); 1735 pw.println(" mNewReasonDataDenied=" + mNewReasonDataDenied); 1736 pw.println(" mGsmRoaming=" + mGsmRoaming); 1737 pw.println(" mDataRoaming=" + mDataRoaming); 1738 pw.println(" mEmergencyOnly=" + mEmergencyOnly); 1739 pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz); 1740 pw.println(" mZoneOffset=" + mZoneOffset); 1741 pw.println(" mZoneDst=" + mZoneDst); 1742 pw.println(" mZoneTime=" + mZoneTime); 1743 pw.println(" mGotCountryCode=" + mGotCountryCode); 1744 pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime); 1745 pw.println(" mSavedTimeZone=" + mSavedTimeZone); 1746 pw.println(" mSavedTime=" + mSavedTime); 1747 pw.println(" mSavedAtTime=" + mSavedAtTime); 1748 pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck); 1749 pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg); 1750 pw.println(" mNotification=" + mNotification); 1751 pw.println(" mWakeLock=" + mWakeLock); 1752 pw.println(" curSpn=" + curSpn); 1753 pw.println(" curShowSpn=" + curShowSpn); 1754 pw.println(" curPlmn=" + curPlmn); 1755 pw.println(" curShowPlmn=" + curShowPlmn); 1756 } 1757} 1758