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