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