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