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