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