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