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