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