ServiceStateTracker.java revision c4161078eff3305894f1f9f1b2f00952ea0e83d8
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; 18 19import android.os.AsyncResult; 20import android.os.Handler; 21import android.os.Message; 22import android.os.Registrant; 23import android.os.RegistrantList; 24import android.os.SystemClock; 25import android.telephony.CellInfo; 26import android.telephony.ServiceState; 27import android.telephony.SignalStrength; 28import android.util.TimeUtils; 29 30import java.io.FileDescriptor; 31import java.io.PrintWriter; 32import java.util.ArrayList; 33import java.util.List; 34 35import com.android.internal.telephony.dataconnection.DcTrackerBase; 36import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; 37import com.android.internal.telephony.uicc.IccRecords; 38import com.android.internal.telephony.uicc.UiccCardApplication; 39import com.android.internal.telephony.uicc.UiccController; 40 41/** 42 * {@hide} 43 */ 44public abstract class ServiceStateTracker extends Handler { 45 protected static final boolean DBG = true; 46 protected static final boolean VDBG = false; 47 48 protected static final String PROP_FORCE_ROAMING = "telephony.test.forceRoaming"; 49 50 protected CommandsInterface mCi; 51 protected UiccController mUiccController = null; 52 protected UiccCardApplication mUiccApplcation = null; 53 protected IccRecords mIccRecords = null; 54 55 protected PhoneBase mPhoneBase; 56 57 protected boolean mVoiceCapable; 58 59 public ServiceState mSS = new ServiceState(); 60 protected ServiceState mNewSS = new ServiceState(); 61 62 private static final long LAST_CELL_INFO_LIST_MAX_AGE_MS = 2000; 63 protected long mLastCellInfoListTime; 64 protected List<CellInfo> mLastCellInfoList = null; 65 66 // This is final as subclasses alias to a more specific type 67 // so we don't want the reference to change. 68 protected final CellInfo mCellInfo; 69 70 protected SignalStrength mSignalStrength = new SignalStrength(); 71 72 // TODO - this should not be public, right now used externally GsmConnetion. 73 public RestrictedState mRestrictedState = new RestrictedState(); 74 75 /* The otaspMode passed to PhoneStateListener#onOtaspChanged */ 76 static public final int OTASP_UNINITIALIZED = 0; 77 static public final int OTASP_UNKNOWN = 1; 78 static public final int OTASP_NEEDED = 2; 79 static public final int OTASP_NOT_NEEDED = 3; 80 81 /** 82 * A unique identifier to track requests associated with a poll 83 * and ignore stale responses. The value is a count-down of 84 * expected responses in this pollingContext. 85 */ 86 protected int[] mPollingContext; 87 protected boolean mDesiredPowerState; 88 89 /** 90 * By default, strength polling is enabled. However, if we're 91 * getting unsolicited signal strength updates from the radio, set 92 * value to true and don't bother polling any more. 93 */ 94 protected boolean mDontPollSignalStrength = false; 95 96 protected RegistrantList mRoamingOnRegistrants = new RegistrantList(); 97 protected RegistrantList mRoamingOffRegistrants = new RegistrantList(); 98 protected RegistrantList mAttachedRegistrants = new RegistrantList(); 99 protected RegistrantList mDetachedRegistrants = new RegistrantList(); 100 protected RegistrantList mNetworkAttachedRegistrants = new RegistrantList(); 101 protected RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList(); 102 protected RegistrantList mPsRestrictDisabledRegistrants = new RegistrantList(); 103 104 /* Radio power off pending flag and tag counter */ 105 private boolean mPendingRadioPowerOffAfterDataOff = false; 106 private int mPendingRadioPowerOffAfterDataOffTag = 0; 107 108 /** Signal strength poll rate. */ 109 protected static final int POLL_PERIOD_MILLIS = 20 * 1000; 110 111 /** Waiting period before recheck gprs and voice registration. */ 112 public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; 113 114 /** GSM events */ 115 protected static final int EVENT_RADIO_STATE_CHANGED = 1; 116 protected static final int EVENT_NETWORK_STATE_CHANGED = 2; 117 protected static final int EVENT_GET_SIGNAL_STRENGTH = 3; 118 protected static final int EVENT_POLL_STATE_REGISTRATION = 4; 119 protected static final int EVENT_POLL_STATE_GPRS = 5; 120 protected static final int EVENT_POLL_STATE_OPERATOR = 6; 121 protected static final int EVENT_POLL_SIGNAL_STRENGTH = 10; 122 protected static final int EVENT_NITZ_TIME = 11; 123 protected static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12; 124 protected static final int EVENT_RADIO_AVAILABLE = 13; 125 protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14; 126 protected static final int EVENT_GET_LOC_DONE = 15; 127 protected static final int EVENT_SIM_RECORDS_LOADED = 16; 128 protected static final int EVENT_SIM_READY = 17; 129 protected static final int EVENT_LOCATION_UPDATES_ENABLED = 18; 130 protected static final int EVENT_GET_PREFERRED_NETWORK_TYPE = 19; 131 protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20; 132 protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21; 133 protected static final int EVENT_CHECK_REPORT_GPRS = 22; 134 protected static final int EVENT_RESTRICTED_STATE_CHANGED = 23; 135 136 /** CDMA events */ 137 protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA = 24; 138 protected static final int EVENT_POLL_STATE_OPERATOR_CDMA = 25; 139 protected static final int EVENT_RUIM_READY = 26; 140 protected static final int EVENT_RUIM_RECORDS_LOADED = 27; 141 protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA = 28; 142 protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA = 29; 143 protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA = 30; 144 protected static final int EVENT_GET_LOC_DONE_CDMA = 31; 145 //protected static final int EVENT_UNUSED = 32; 146 protected static final int EVENT_NV_LOADED = 33; 147 protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION = 34; 148 protected static final int EVENT_NV_READY = 35; 149 protected static final int EVENT_ERI_FILE_LOADED = 36; 150 protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 37; 151 protected static final int EVENT_SET_RADIO_POWER_OFF = 38; 152 protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 39; 153 protected static final int EVENT_CDMA_PRL_VERSION_CHANGED = 40; 154 protected static final int EVENT_RADIO_ON = 41; 155 protected static final int EVENT_ICC_CHANGED = 42; 156 protected static final int EVENT_GET_CELL_INFO_LIST = 43; 157 protected static final int EVENT_UNSOL_CELL_INFO_LIST = 44; 158 159 protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; 160 161 /** 162 * List of ISO codes for countries that can have an offset of 163 * GMT+0 when not in daylight savings time. This ignores some 164 * small places such as the Canary Islands (Spain) and 165 * Danmarkshavn (Denmark). The list must be sorted by code. 166 */ 167 protected static final String[] GMT_COUNTRY_CODES = { 168 "bf", // Burkina Faso 169 "ci", // Cote d'Ivoire 170 "eh", // Western Sahara 171 "fo", // Faroe Islands, Denmark 172 "gb", // United Kingdom of Great Britain and Northern Ireland 173 "gh", // Ghana 174 "gm", // Gambia 175 "gn", // Guinea 176 "gw", // Guinea Bissau 177 "ie", // Ireland 178 "lr", // Liberia 179 "is", // Iceland 180 "ma", // Morocco 181 "ml", // Mali 182 "mr", // Mauritania 183 "pt", // Portugal 184 "sl", // Sierra Leone 185 "sn", // Senegal 186 "st", // Sao Tome and Principe 187 "tg", // Togo 188 }; 189 190 private class CellInfoResult { 191 List<CellInfo> list; 192 Object lockObj = new Object(); 193 } 194 195 /** Reason for registration denial. */ 196 protected static final String REGISTRATION_DENIED_GEN = "General"; 197 protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure"; 198 199 protected ServiceStateTracker(PhoneBase phoneBase, CommandsInterface ci, CellInfo cellInfo) { 200 mPhoneBase = phoneBase; 201 mCellInfo = cellInfo; 202 mCi = ci; 203 mVoiceCapable = mPhoneBase.getContext().getResources().getBoolean( 204 com.android.internal.R.bool.config_voice_capable); 205 mUiccController = UiccController.getInstance(); 206 mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); 207 mCi.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); 208 mCi.registerForCellInfoList(this, EVENT_UNSOL_CELL_INFO_LIST, null); 209 210 mPhoneBase.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 211 ServiceState.rilRadioTechnologyToString(ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)); 212 } 213 214 public void dispose() { 215 mCi.unSetOnSignalStrengthUpdate(this); 216 mUiccController.unregisterForIccChanged(this); 217 mCi.unregisterForCellInfoList(this); 218 } 219 220 public boolean getDesiredPowerState() { 221 return mDesiredPowerState; 222 } 223 224 private SignalStrength mLastSignalStrength = null; 225 protected boolean notifySignalStrength() { 226 boolean notified = false; 227 synchronized(mCellInfo) { 228 if (!mSignalStrength.equals(mLastSignalStrength)) { 229 try { 230 mPhoneBase.notifySignalStrength(); 231 notified = true; 232 } catch (NullPointerException ex) { 233 loge("updateSignalStrength() Phone already destroyed: " + ex 234 + "SignalStrength not notified"); 235 } 236 } 237 } 238 return notified; 239 } 240 241 /** 242 * Some operators have been known to report registration failure 243 * data only devices, to fix that use DataRegState. 244 */ 245 protected void useDataRegStateForDataOnlyDevices() { 246 if (mVoiceCapable == false) { 247 if (DBG) { 248 log("useDataRegStateForDataOnlyDevice: VoiceRegState=" + mNewSS.getVoiceRegState() 249 + " DataRegState=" + mNewSS.getDataRegState()); 250 } 251 // TODO: Consider not lying and instead have callers know the difference. 252 mNewSS.setVoiceRegState(mNewSS.getDataRegState()); 253 } 254 } 255 256 257 /** 258 * Registration point for combined roaming on 259 * combined roaming is true when roaming is true and ONS differs SPN 260 * 261 * @param h handler to notify 262 * @param what what code of message when delivered 263 * @param obj placed in Message.obj 264 */ 265 public void registerForRoamingOn(Handler h, int what, Object obj) { 266 Registrant r = new Registrant(h, what, obj); 267 mRoamingOnRegistrants.add(r); 268 269 if (mSS.getRoaming()) { 270 r.notifyRegistrant(); 271 } 272 } 273 274 public void unregisterForRoamingOn(Handler h) { 275 mRoamingOnRegistrants.remove(h); 276 } 277 278 /** 279 * Registration point for combined roaming off 280 * combined roaming is true when roaming is true and ONS differs SPN 281 * 282 * @param h handler to notify 283 * @param what what code of message when delivered 284 * @param obj placed in Message.obj 285 */ 286 public void registerForRoamingOff(Handler h, int what, Object obj) { 287 Registrant r = new Registrant(h, what, obj); 288 mRoamingOffRegistrants.add(r); 289 290 if (!mSS.getRoaming()) { 291 r.notifyRegistrant(); 292 } 293 } 294 295 public void unregisterForRoamingOff(Handler h) { 296 mRoamingOffRegistrants.remove(h); 297 } 298 299 /** 300 * Re-register network by toggling preferred network type. 301 * This is a work-around to deregister and register network since there is 302 * no ril api to set COPS=2 (deregister) only. 303 * 304 * @param onComplete is dispatched when this is complete. it will be 305 * an AsyncResult, and onComplete.obj.exception will be non-null 306 * on failure. 307 */ 308 public void reRegisterNetwork(Message onComplete) { 309 mCi.getPreferredNetworkType( 310 obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete)); 311 } 312 313 public void 314 setRadioPower(boolean power) { 315 mDesiredPowerState = power; 316 317 setPowerStateToDesired(); 318 } 319 320 /** 321 * These two flags manage the behavior of the cell lock -- the 322 * lock should be held if either flag is true. The intention is 323 * to allow temporary acquisition of the lock to get a single 324 * update. Such a lock grab and release can thus be made to not 325 * interfere with more permanent lock holds -- in other words, the 326 * lock will only be released if both flags are false, and so 327 * releases by temporary users will only affect the lock state if 328 * there is no continuous user. 329 */ 330 private boolean mWantContinuousLocationUpdates; 331 private boolean mWantSingleLocationUpdate; 332 333 public void enableSingleLocationUpdate() { 334 if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return; 335 mWantSingleLocationUpdate = true; 336 mCi.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED)); 337 } 338 339 public void enableLocationUpdates() { 340 if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return; 341 mWantContinuousLocationUpdates = true; 342 mCi.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED)); 343 } 344 345 protected void disableSingleLocationUpdate() { 346 mWantSingleLocationUpdate = false; 347 if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) { 348 mCi.setLocationUpdates(false, null); 349 } 350 } 351 352 public void disableLocationUpdates() { 353 mWantContinuousLocationUpdates = false; 354 if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) { 355 mCi.setLocationUpdates(false, null); 356 } 357 } 358 359 @Override 360 public void handleMessage(Message msg) { 361 switch (msg.what) { 362 case EVENT_SET_RADIO_POWER_OFF: 363 synchronized(this) { 364 if (mPendingRadioPowerOffAfterDataOff && 365 (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) { 366 if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); 367 hangupAndPowerOff(); 368 mPendingRadioPowerOffAfterDataOffTag += 1; 369 mPendingRadioPowerOffAfterDataOff = false; 370 } else { 371 log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 + 372 "!= tag=" + mPendingRadioPowerOffAfterDataOffTag); 373 } 374 } 375 break; 376 377 case EVENT_ICC_CHANGED: 378 onUpdateIccAvailability(); 379 break; 380 381 case EVENT_GET_CELL_INFO_LIST: { 382 AsyncResult ar = (AsyncResult) msg.obj; 383 CellInfoResult result = (CellInfoResult) ar.userObj; 384 synchronized(result.lockObj) { 385 if (ar.exception != null) { 386 log("EVENT_GET_CELL_INFO_LIST: error ret null, e=" + ar.exception); 387 result.list = null; 388 } else { 389 result.list = (List<CellInfo>) ar.result; 390 391 if (VDBG) { 392 log("EVENT_GET_CELL_INFO_LIST: size=" + result.list.size() 393 + " list=" + result.list); 394 } 395 } 396 mLastCellInfoListTime = SystemClock.elapsedRealtime(); 397 mLastCellInfoList = result.list; 398 result.lockObj.notify(); 399 } 400 break; 401 } 402 403 case EVENT_UNSOL_CELL_INFO_LIST: { 404 AsyncResult ar = (AsyncResult) msg.obj; 405 if (ar.exception != null) { 406 log("EVENT_UNSOL_CELL_INFO_LIST: error ignoring, e=" + ar.exception); 407 } else { 408 List<CellInfo> list = (List<CellInfo>) ar.result; 409 if (DBG) { 410 log("EVENT_UNSOL_CELL_INFO_LIST: size=" + list.size() 411 + " list=" + list); 412 } 413 mLastCellInfoListTime = SystemClock.elapsedRealtime(); 414 mLastCellInfoList = list; 415 mPhoneBase.notifyCellInfo(list); 416 } 417 break; 418 } 419 420 default: 421 log("Unhandled message with number: " + msg.what); 422 break; 423 } 424 } 425 426 protected abstract Phone getPhone(); 427 protected abstract void handlePollStateResult(int what, AsyncResult ar); 428 protected abstract void updateSpnDisplay(); 429 protected abstract void setPowerStateToDesired(); 430 protected abstract void onUpdateIccAvailability(); 431 protected abstract void log(String s); 432 protected abstract void loge(String s); 433 434 public abstract int getCurrentDataConnectionState(); 435 public abstract boolean isConcurrentVoiceAndDataAllowed(); 436 437 /** 438 * Registration point for transition into DataConnection attached. 439 * @param h handler to notify 440 * @param what what code of message when delivered 441 * @param obj placed in Message.obj 442 */ 443 public void registerForDataConnectionAttached(Handler h, int what, Object obj) { 444 Registrant r = new Registrant(h, what, obj); 445 mAttachedRegistrants.add(r); 446 447 if (getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) { 448 r.notifyRegistrant(); 449 } 450 } 451 public void unregisterForDataConnectionAttached(Handler h) { 452 mAttachedRegistrants.remove(h); 453 } 454 455 /** 456 * Registration point for transition into DataConnection detached. 457 * @param h handler to notify 458 * @param what what code of message when delivered 459 * @param obj placed in Message.obj 460 */ 461 public void registerForDataConnectionDetached(Handler h, int what, Object obj) { 462 Registrant r = new Registrant(h, what, obj); 463 mDetachedRegistrants.add(r); 464 465 if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) { 466 r.notifyRegistrant(); 467 } 468 } 469 public void unregisterForDataConnectionDetached(Handler h) { 470 mDetachedRegistrants.remove(h); 471 } 472 473 /** 474 * Registration point for transition into network attached. 475 * @param h handler to notify 476 * @param what what code of message when delivered 477 * @param obj in Message.obj 478 */ 479 public void registerForNetworkAttached(Handler h, int what, Object obj) { 480 Registrant r = new Registrant(h, what, obj); 481 482 mNetworkAttachedRegistrants.add(r); 483 if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { 484 r.notifyRegistrant(); 485 } 486 } 487 public void unregisterForNetworkAttached(Handler h) { 488 mNetworkAttachedRegistrants.remove(h); 489 } 490 491 /** 492 * Registration point for transition into packet service restricted zone. 493 * @param h handler to notify 494 * @param what what code of message when delivered 495 * @param obj placed in Message.obj 496 */ 497 public void registerForPsRestrictedEnabled(Handler h, int what, Object obj) { 498 Registrant r = new Registrant(h, what, obj); 499 mPsRestrictEnabledRegistrants.add(r); 500 501 if (mRestrictedState.isPsRestricted()) { 502 r.notifyRegistrant(); 503 } 504 } 505 506 public void unregisterForPsRestrictedEnabled(Handler h) { 507 mPsRestrictEnabledRegistrants.remove(h); 508 } 509 510 /** 511 * Registration point for transition out of packet service restricted zone. 512 * @param h handler to notify 513 * @param what what code of message when delivered 514 * @param obj placed in Message.obj 515 */ 516 public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) { 517 Registrant r = new Registrant(h, what, obj); 518 mPsRestrictDisabledRegistrants.add(r); 519 520 if (mRestrictedState.isPsRestricted()) { 521 r.notifyRegistrant(); 522 } 523 } 524 525 public void unregisterForPsRestrictedDisabled(Handler h) { 526 mPsRestrictDisabledRegistrants.remove(h); 527 } 528 529 /** 530 * Clean up existing voice and data connection then turn off radio power. 531 * 532 * Hang up the existing voice calls to decrease call drop rate. 533 */ 534 public void powerOffRadioSafely(DcTrackerBase dcTracker) { 535 synchronized (this) { 536 if (!mPendingRadioPowerOffAfterDataOff) { 537 // To minimize race conditions we call cleanUpAllConnections on 538 // both if else paths instead of before this isDisconnected test. 539 if (dcTracker.isDisconnected()) { 540 // To minimize race conditions we do this after isDisconnected 541 dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF); 542 if (DBG) log("Data disconnected, turn off radio right away."); 543 hangupAndPowerOff(); 544 } else { 545 dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF); 546 Message msg = Message.obtain(this); 547 msg.what = EVENT_SET_RADIO_POWER_OFF; 548 msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; 549 if (sendMessageDelayed(msg, 30000)) { 550 if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio."); 551 mPendingRadioPowerOffAfterDataOff = true; 552 } else { 553 log("Cannot send delayed Msg, turn off radio right away."); 554 hangupAndPowerOff(); 555 } 556 } 557 } 558 } 559 } 560 561 /** 562 * process the pending request to turn radio off after data is disconnected 563 * 564 * return true if there is pending request to process; false otherwise. 565 */ 566 public boolean processPendingRadioPowerOffAfterDataOff() { 567 synchronized(this) { 568 if (mPendingRadioPowerOffAfterDataOff) { 569 if (DBG) log("Process pending request to turn radio off."); 570 mPendingRadioPowerOffAfterDataOffTag += 1; 571 hangupAndPowerOff(); 572 mPendingRadioPowerOffAfterDataOff = false; 573 return true; 574 } 575 return false; 576 } 577 } 578 579 /** 580 * send signal-strength-changed notification if changed Called both for 581 * solicited and unsolicited signal strength updates 582 * 583 * @return true if the signal strength changed and a notification was sent. 584 */ 585 protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) { 586 SignalStrength oldSignalStrength = mSignalStrength; 587 588 // This signal is used for both voice and data radio signal so parse 589 // all fields 590 591 if ((ar.exception == null) && (ar.result != null)) { 592 mSignalStrength = (SignalStrength) ar.result; 593 mSignalStrength.validateInput(); 594 mSignalStrength.setGsm(isGsm); 595 } else { 596 log("onSignalStrengthResult() Exception from RIL : " + ar.exception); 597 mSignalStrength = new SignalStrength(isGsm); 598 } 599 600 return notifySignalStrength(); 601 } 602 603 /** 604 * Hang up all voice call and turn off radio. Implemented by derived class. 605 */ 606 protected abstract void hangupAndPowerOff(); 607 608 /** Cancel a pending (if any) pollState() operation */ 609 protected void cancelPollState() { 610 // This will effectively cancel the rest of the poll requests. 611 mPollingContext = new int[1]; 612 } 613 614 /** 615 * Return true if time zone needs fixing. 616 * 617 * @param phoneBase 618 * @param operatorNumeric 619 * @param prevOperatorNumeric 620 * @param needToFixTimeZone 621 * @return true if time zone needs to be fixed 622 */ 623 protected boolean shouldFixTimeZoneNow(PhoneBase phoneBase, String operatorNumeric, 624 String prevOperatorNumeric, boolean needToFixTimeZone) { 625 // Return false if the mcc isn't valid as we don't know where we are. 626 // Return true if we have an IccCard and the mcc changed or we 627 // need to fix it because when the NITZ time came in we didn't 628 // know the country code. 629 630 // If mcc is invalid then we'll return false 631 int mcc; 632 try { 633 mcc = Integer.parseInt(operatorNumeric.substring(0, 3)); 634 } catch (Exception e) { 635 if (DBG) { 636 log("shouldFixTimeZoneNow: no mcc, operatorNumeric=" + operatorNumeric + 637 " retVal=false"); 638 } 639 return false; 640 } 641 642 // If prevMcc is invalid will make it different from mcc 643 // so we'll return true if the card exists. 644 int prevMcc; 645 try { 646 prevMcc = Integer.parseInt(prevOperatorNumeric.substring(0, 3)); 647 } catch (Exception e) { 648 prevMcc = mcc + 1; 649 } 650 651 // Determine if the Icc card exists 652 boolean iccCardExist = false; 653 if (mUiccApplcation != null) { 654 iccCardExist = mUiccApplcation.getState() != AppState.APPSTATE_UNKNOWN; 655 } 656 657 // Determine retVal 658 boolean retVal = ((iccCardExist && (mcc != prevMcc)) || needToFixTimeZone); 659 if (DBG) { 660 long ctm = System.currentTimeMillis(); 661 log("shouldFixTimeZoneNow: retVal=" + retVal + 662 " iccCardExist=" + iccCardExist + 663 " operatorNumeric=" + operatorNumeric + " mcc=" + mcc + 664 " prevOperatorNumeric=" + prevOperatorNumeric + " prevMcc=" + prevMcc + 665 " needToFixTimeZone=" + needToFixTimeZone + 666 " ltod=" + TimeUtils.logTimeOfDay(ctm)); 667 } 668 return retVal; 669 } 670 671 /** 672 * @return all available cell information or null if none. 673 */ 674 public List<CellInfo> getAllCellInfo() { 675 CellInfoResult result = new CellInfoResult(); 676 if (VDBG) log("SST.getAllCellInfo(): E"); 677 int ver = mCi.getRilVersion(); 678 if (ver >= 8) { 679 if (isCallerOnDifferentThread()) { 680 if ((SystemClock.elapsedRealtime() - mLastCellInfoListTime) 681 > LAST_CELL_INFO_LIST_MAX_AGE_MS) { 682 Message msg = obtainMessage(EVENT_GET_CELL_INFO_LIST, result); 683 synchronized(result.lockObj) { 684 mCi.getCellInfoList(msg); 685 try { 686 result.lockObj.wait(); 687 } catch (InterruptedException e) { 688 e.printStackTrace(); 689 result.list = null; 690 } 691 } 692 } else { 693 if (DBG) log("SST.getAllCellInfo(): return last, back to back calls"); 694 result.list = mLastCellInfoList; 695 } 696 } else { 697 if (DBG) log("SST.getAllCellInfo(): return last, same thread can't block"); 698 result.list = mLastCellInfoList; 699 } 700 } else { 701 if (DBG) log("SST.getAllCellInfo(): not implemented"); 702 result.list = null; 703 } 704 if (DBG) { 705 if (result.list != null) { 706 log("SST.getAllCellInfo(): X size=" + result.list.size() 707 + " list=" + result.list); 708 } else { 709 log("SST.getAllCellInfo(): X size=0 list=null"); 710 } 711 } 712 return result.list; 713 } 714 715 /** 716 * @return signal strength 717 */ 718 public SignalStrength getSignalStrength() { 719 synchronized(mCellInfo) { 720 return mSignalStrength; 721 } 722 } 723 724 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 725 pw.println("ServiceStateTracker:"); 726 pw.println(" mSS=" + mSS); 727 pw.println(" mNewSS=" + mNewSS); 728 pw.println(" mCellInfo=" + mCellInfo); 729 pw.println(" mRestrictedState=" + mRestrictedState); 730 pw.println(" mPollingContext=" + mPollingContext); 731 pw.println(" mDesiredPowerState=" + mDesiredPowerState); 732 pw.println(" mDontPollSignalStrength=" + mDontPollSignalStrength); 733 pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff); 734 pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag); 735 } 736 737 /** 738 * Verifies the current thread is the same as the thread originally 739 * used in the initialization of this instance. Throws RuntimeException 740 * if not. 741 * 742 * @exception RuntimeException if the current thread is not 743 * the thread that originally obtained this PhoneBase instance. 744 */ 745 protected void checkCorrectThread() { 746 if (Thread.currentThread() != getLooper().getThread()) { 747 throw new RuntimeException( 748 "ServiceStateTracker must be used from within one thread"); 749 } 750 } 751 752 protected boolean isCallerOnDifferentThread() { 753 boolean value = Thread.currentThread() != getLooper().getThread(); 754 if (VDBG) log("isCallerOnDifferentThread: " + value); 755 return value; 756 } 757} 758