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