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