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