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