ServiceStateTracker.java revision ef1d4bff9bbf7d967dbcace73f08910e14e367d0
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony; 18 19import android.os.AsyncResult; 20import android.os.Handler; 21import android.os.Message; 22import android.os.Registrant; 23import android.os.RegistrantList; 24import android.os.SystemClock; 25import android.telephony.CellInfo; 26import android.telephony.ServiceState; 27import android.telephony.SignalStrength; 28import android.util.TimeUtils; 29 30import java.io.FileDescriptor; 31import java.io.PrintWriter; 32import java.util.List; 33 34/** 35 * {@hide} 36 */ 37public abstract class ServiceStateTracker extends Handler { 38 39 protected CommandsInterface cm; 40 41 protected PhoneBase mPhoneBase; 42 43 public ServiceState ss = new ServiceState(); 44 protected ServiceState newSS = new ServiceState(); 45 46 protected CellInfo mLastCellInfo = null; 47 48 // This is final as subclasses alias to a more specific type 49 // so we don't want the reference to change. 50 protected final CellInfo mCellInfo; 51 52 protected SignalStrength mSignalStrength = new SignalStrength(); 53 54 // TODO - this should not be public, right now used externally GsmConnetion. 55 public RestrictedState mRestrictedState = new RestrictedState(); 56 57 /* The otaspMode passed to PhoneStateListener#onOtaspChanged */ 58 static public final int OTASP_UNINITIALIZED = 0; 59 static public final int OTASP_UNKNOWN = 1; 60 static public final int OTASP_NEEDED = 2; 61 static public final int OTASP_NOT_NEEDED = 3; 62 63 /** 64 * A unique identifier to track requests associated with a poll 65 * and ignore stale responses. The value is a count-down of 66 * expected responses in this pollingContext. 67 */ 68 protected int[] pollingContext; 69 protected boolean mDesiredPowerState; 70 71 /** 72 * Values correspond to ServiceState.RIL_RADIO_TECHNOLOGY_ definitions. 73 */ 74 protected int mRilRadioTechnology = 0; 75 protected int mNewRilRadioTechnology = 0; 76 77 /** 78 * By default, strength polling is enabled. However, if we're 79 * getting unsolicited signal strength updates from the radio, set 80 * value to true and don't bother polling any more. 81 */ 82 protected boolean dontPollSignalStrength = false; 83 84 protected RegistrantList mRoamingOnRegistrants = new RegistrantList(); 85 protected RegistrantList mRoamingOffRegistrants = new RegistrantList(); 86 protected RegistrantList mAttachedRegistrants = new RegistrantList(); 87 protected RegistrantList mDetachedRegistrants = new RegistrantList(); 88 protected RegistrantList mNetworkAttachedRegistrants = new RegistrantList(); 89 protected RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList(); 90 protected RegistrantList mPsRestrictDisabledRegistrants = new RegistrantList(); 91 92 /* Radio power off pending flag and tag counter */ 93 private boolean mPendingRadioPowerOffAfterDataOff = false; 94 private int mPendingRadioPowerOffAfterDataOffTag = 0; 95 96 protected static final boolean DBG = true; 97 98 /** Signal strength poll rate. */ 99 protected static final int POLL_PERIOD_MILLIS = 20 * 1000; 100 101 /** Waiting period before recheck gprs and voice registration. */ 102 public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; 103 104 /** GSM events */ 105 protected static final int EVENT_RADIO_STATE_CHANGED = 1; 106 protected static final int EVENT_NETWORK_STATE_CHANGED = 2; 107 protected static final int EVENT_GET_SIGNAL_STRENGTH = 3; 108 protected static final int EVENT_POLL_STATE_REGISTRATION = 4; 109 protected static final int EVENT_POLL_STATE_GPRS = 5; 110 protected static final int EVENT_POLL_STATE_OPERATOR = 6; 111 protected static final int EVENT_POLL_SIGNAL_STRENGTH = 10; 112 protected static final int EVENT_NITZ_TIME = 11; 113 protected static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12; 114 protected static final int EVENT_RADIO_AVAILABLE = 13; 115 protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14; 116 protected static final int EVENT_GET_LOC_DONE = 15; 117 protected static final int EVENT_SIM_RECORDS_LOADED = 16; 118 protected static final int EVENT_SIM_READY = 17; 119 protected static final int EVENT_LOCATION_UPDATES_ENABLED = 18; 120 protected static final int EVENT_GET_PREFERRED_NETWORK_TYPE = 19; 121 protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20; 122 protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21; 123 protected static final int EVENT_CHECK_REPORT_GPRS = 22; 124 protected static final int EVENT_RESTRICTED_STATE_CHANGED = 23; 125 126 /** CDMA events */ 127 protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA = 24; 128 protected static final int EVENT_POLL_STATE_OPERATOR_CDMA = 25; 129 protected static final int EVENT_RUIM_READY = 26; 130 protected static final int EVENT_RUIM_RECORDS_LOADED = 27; 131 protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA = 28; 132 protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA = 29; 133 protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA = 30; 134 protected static final int EVENT_GET_LOC_DONE_CDMA = 31; 135 //protected static final int EVENT_UNUSED = 32; 136 protected static final int EVENT_NV_LOADED = 33; 137 protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION = 34; 138 protected static final int EVENT_NV_READY = 35; 139 protected static final int EVENT_ERI_FILE_LOADED = 36; 140 protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 37; 141 protected static final int EVENT_SET_RADIO_POWER_OFF = 38; 142 protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 39; 143 protected static final int EVENT_CDMA_PRL_VERSION_CHANGED = 40; 144 protected static final int EVENT_RADIO_ON = 41; 145 146 147 protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; 148 149 /** 150 * List of ISO codes for countries that can have an offset of 151 * GMT+0 when not in daylight savings time. This ignores some 152 * small places such as the Canary Islands (Spain) and 153 * Danmarkshavn (Denmark). The list must be sorted by code. 154 */ 155 protected static final String[] GMT_COUNTRY_CODES = { 156 "bf", // Burkina Faso 157 "ci", // Cote d'Ivoire 158 "eh", // Western Sahara 159 "fo", // Faroe Islands, Denmark 160 "gb", // United Kingdom of Great Britain and Northern Ireland 161 "gh", // Ghana 162 "gm", // Gambia 163 "gn", // Guinea 164 "gw", // Guinea Bissau 165 "ie", // Ireland 166 "lr", // Liberia 167 "is", // Iceland 168 "ma", // Morocco 169 "ml", // Mali 170 "mr", // Mauritania 171 "pt", // Portugal 172 "sl", // Sierra Leone 173 "sn", // Senegal 174 "st", // Sao Tome and Principe 175 "tg", // Togo 176 }; 177 178 /** Reason for registration denial. */ 179 protected static final String REGISTRATION_DENIED_GEN = "General"; 180 protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure"; 181 182 protected ServiceStateTracker(PhoneBase phoneBase, CellInfo cellInfo) { 183 mPhoneBase = phoneBase; 184 mCellInfo = cellInfo; 185 cm = mPhoneBase.mCM; 186 cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); 187 } 188 189 public void dispose() { 190 cm.unSetOnSignalStrengthUpdate(this); 191 } 192 193 public boolean getDesiredPowerState() { 194 return mDesiredPowerState; 195 } 196 197 private SignalStrength mLastSignalStrength = null; 198 protected boolean notifySignalStrength() { 199 boolean notified = false; 200 synchronized(mCellInfo) { 201 if (!mSignalStrength.equals(mLastSignalStrength)) { 202 try { 203 mPhoneBase.notifySignalStrength(); 204 notified = true; 205 } catch (NullPointerException ex) { 206 loge("updateSignalStrength() Phone already destroyed: " + ex 207 + "SignalStrength not notified"); 208 } 209 } 210 } 211 return notified; 212 } 213 214 /** 215 * Set the mCellInfo.signalStrength to its default values 216 */ 217 protected void setSignalStrengthDefaultValues() { 218 setSignalStrengthDefaultValues(mSignalStrength); 219 } 220 221 /** 222 * Set the signal strength default values 223 */ 224 protected void setSignalStrengthDefaultValues(SignalStrength signalStrength) { 225 signalStrength.initialize(99, -1, -1, -1, -1, -1, -1, 226 -1, -1, -1, SignalStrength.INVALID_SNR, -1, isGsmSignalStrength()); 227 } 228 229 /** 230 * Return true if this SST is a GSM category device. 231 */ 232 protected abstract boolean isGsmSignalStrength(); 233 234 /** 235 * Registration point for combined roaming on 236 * combined roaming is true when roaming is true and ONS differs SPN 237 * 238 * @param h handler to notify 239 * @param what what code of message when delivered 240 * @param obj placed in Message.obj 241 */ 242 public void registerForRoamingOn(Handler h, int what, Object obj) { 243 Registrant r = new Registrant(h, what, obj); 244 mRoamingOnRegistrants.add(r); 245 246 if (ss.getRoaming()) { 247 r.notifyRegistrant(); 248 } 249 } 250 251 public void unregisterForRoamingOn(Handler h) { 252 mRoamingOnRegistrants.remove(h); 253 } 254 255 /** 256 * Registration point for combined roaming off 257 * combined roaming is true when roaming is true and ONS differs SPN 258 * 259 * @param h handler to notify 260 * @param what what code of message when delivered 261 * @param obj placed in Message.obj 262 */ 263 public void registerForRoamingOff(Handler h, int what, Object obj) { 264 Registrant r = new Registrant(h, what, obj); 265 mRoamingOffRegistrants.add(r); 266 267 if (!ss.getRoaming()) { 268 r.notifyRegistrant(); 269 } 270 } 271 272 public void unregisterForRoamingOff(Handler h) { 273 mRoamingOffRegistrants.remove(h); 274 } 275 276 /** 277 * Re-register network by toggling preferred network type. 278 * This is a work-around to deregister and register network since there is 279 * no ril api to set COPS=2 (deregister) only. 280 * 281 * @param onComplete is dispatched when this is complete. it will be 282 * an AsyncResult, and onComplete.obj.exception will be non-null 283 * on failure. 284 */ 285 public void reRegisterNetwork(Message onComplete) { 286 cm.getPreferredNetworkType( 287 obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete)); 288 } 289 290 public void 291 setRadioPower(boolean power) { 292 mDesiredPowerState = power; 293 294 setPowerStateToDesired(); 295 } 296 297 /** 298 * These two flags manage the behavior of the cell lock -- the 299 * lock should be held if either flag is true. The intention is 300 * to allow temporary acquisition of the lock to get a single 301 * update. Such a lock grab and release can thus be made to not 302 * interfere with more permanent lock holds -- in other words, the 303 * lock will only be released if both flags are false, and so 304 * releases by temporary users will only affect the lock state if 305 * there is no continuous user. 306 */ 307 private boolean mWantContinuousLocationUpdates; 308 private boolean mWantSingleLocationUpdate; 309 310 public void enableSingleLocationUpdate() { 311 if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return; 312 mWantSingleLocationUpdate = true; 313 cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED)); 314 } 315 316 public void enableLocationUpdates() { 317 if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return; 318 mWantContinuousLocationUpdates = true; 319 cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED)); 320 } 321 322 protected void disableSingleLocationUpdate() { 323 mWantSingleLocationUpdate = false; 324 if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) { 325 cm.setLocationUpdates(false, null); 326 } 327 } 328 329 public void disableLocationUpdates() { 330 mWantContinuousLocationUpdates = false; 331 if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) { 332 cm.setLocationUpdates(false, null); 333 } 334 } 335 336 @Override 337 public void handleMessage(Message msg) { 338 switch (msg.what) { 339 case EVENT_SET_RADIO_POWER_OFF: 340 synchronized(this) { 341 if (mPendingRadioPowerOffAfterDataOff && 342 (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) { 343 if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); 344 hangupAndPowerOff(); 345 mPendingRadioPowerOffAfterDataOffTag += 1; 346 mPendingRadioPowerOffAfterDataOff = false; 347 } else { 348 log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 + 349 "!= tag=" + mPendingRadioPowerOffAfterDataOffTag); 350 } 351 } 352 break; 353 354 default: 355 log("Unhandled message with number: " + msg.what); 356 break; 357 } 358 } 359 360 protected abstract Phone getPhone(); 361 protected abstract void handlePollStateResult(int what, AsyncResult ar); 362 protected abstract void updateSpnDisplay(); 363 protected abstract void setPowerStateToDesired(); 364 protected abstract void log(String s); 365 protected abstract void loge(String s); 366 367 public abstract int getCurrentDataConnectionState(); 368 public abstract boolean isConcurrentVoiceAndDataAllowed(); 369 370 /** 371 * Registration point for transition into DataConnection attached. 372 * @param h handler to notify 373 * @param what what code of message when delivered 374 * @param obj placed in Message.obj 375 */ 376 public void registerForDataConnectionAttached(Handler h, int what, Object obj) { 377 Registrant r = new Registrant(h, what, obj); 378 mAttachedRegistrants.add(r); 379 380 if (getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) { 381 r.notifyRegistrant(); 382 } 383 } 384 public void unregisterForDataConnectionAttached(Handler h) { 385 mAttachedRegistrants.remove(h); 386 } 387 388 /** 389 * Registration point for transition into DataConnection detached. 390 * @param h handler to notify 391 * @param what what code of message when delivered 392 * @param obj placed in Message.obj 393 */ 394 public void registerForDataConnectionDetached(Handler h, int what, Object obj) { 395 Registrant r = new Registrant(h, what, obj); 396 mDetachedRegistrants.add(r); 397 398 if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) { 399 r.notifyRegistrant(); 400 } 401 } 402 public void unregisterForDataConnectionDetached(Handler h) { 403 mDetachedRegistrants.remove(h); 404 } 405 406 /** 407 * Registration point for transition into network attached. 408 * @param h handler to notify 409 * @param what what code of message when delivered 410 * @param obj in Message.obj 411 */ 412 public void registerForNetworkAttached(Handler h, int what, Object obj) { 413 Registrant r = new Registrant(h, what, obj); 414 415 mNetworkAttachedRegistrants.add(r); 416 if (ss.getState() == ServiceState.STATE_IN_SERVICE) { 417 r.notifyRegistrant(); 418 } 419 } 420 public void unregisterForNetworkAttached(Handler h) { 421 mNetworkAttachedRegistrants.remove(h); 422 } 423 424 /** 425 * Registration point for transition into packet service restricted zone. 426 * @param h handler to notify 427 * @param what what code of message when delivered 428 * @param obj placed in Message.obj 429 */ 430 public void registerForPsRestrictedEnabled(Handler h, int what, Object obj) { 431 Registrant r = new Registrant(h, what, obj); 432 mPsRestrictEnabledRegistrants.add(r); 433 434 if (mRestrictedState.isPsRestricted()) { 435 r.notifyRegistrant(); 436 } 437 } 438 439 public void unregisterForPsRestrictedEnabled(Handler h) { 440 mPsRestrictEnabledRegistrants.remove(h); 441 } 442 443 /** 444 * Registration point for transition out of packet service restricted zone. 445 * @param h handler to notify 446 * @param what what code of message when delivered 447 * @param obj placed in Message.obj 448 */ 449 public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) { 450 Registrant r = new Registrant(h, what, obj); 451 mPsRestrictDisabledRegistrants.add(r); 452 453 if (mRestrictedState.isPsRestricted()) { 454 r.notifyRegistrant(); 455 } 456 } 457 458 public void unregisterForPsRestrictedDisabled(Handler h) { 459 mPsRestrictDisabledRegistrants.remove(h); 460 } 461 462 /** 463 * Clean up existing voice and data connection then turn off radio power. 464 * 465 * Hang up the existing voice calls to decrease call drop rate. 466 */ 467 public void powerOffRadioSafely(DataConnectionTracker dcTracker) { 468 synchronized (this) { 469 if (!mPendingRadioPowerOffAfterDataOff) { 470 // To minimize race conditions we call cleanUpAllConnections on 471 // both if else paths instead of before this isDisconnected test. 472 if (dcTracker.isDisconnected()) { 473 // To minimize race conditions we do this after isDisconnected 474 dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF); 475 if (DBG) log("Data disconnected, turn off radio right away."); 476 hangupAndPowerOff(); 477 } else { 478 dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF); 479 Message msg = Message.obtain(this); 480 msg.what = EVENT_SET_RADIO_POWER_OFF; 481 msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; 482 if (sendMessageDelayed(msg, 30000)) { 483 if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio."); 484 mPendingRadioPowerOffAfterDataOff = true; 485 } else { 486 log("Cannot send delayed Msg, turn off radio right away."); 487 hangupAndPowerOff(); 488 } 489 } 490 } 491 } 492 } 493 494 /** 495 * process the pending request to turn radio off after data is disconnected 496 * 497 * return true if there is pending request to process; false otherwise. 498 */ 499 public boolean processPendingRadioPowerOffAfterDataOff() { 500 synchronized(this) { 501 if (mPendingRadioPowerOffAfterDataOff) { 502 if (DBG) log("Process pending request to turn radio off."); 503 mPendingRadioPowerOffAfterDataOffTag += 1; 504 hangupAndPowerOff(); 505 mPendingRadioPowerOffAfterDataOff = false; 506 return true; 507 } 508 return false; 509 } 510 } 511 512 /** 513 * Hang up all voice call and turn off radio. Implemented by derived class. 514 */ 515 protected abstract void hangupAndPowerOff(); 516 517 /** Cancel a pending (if any) pollState() operation */ 518 protected void cancelPollState() { 519 // This will effectively cancel the rest of the poll requests. 520 pollingContext = new int[1]; 521 } 522 523 /** 524 * Return true if time zone needs fixing. 525 * 526 * @param phoneBase 527 * @param operatorNumeric 528 * @param prevOperatorNumeric 529 * @param needToFixTimeZone 530 * @return true if time zone needs to be fixed 531 */ 532 protected boolean shouldFixTimeZoneNow(PhoneBase phoneBase, String operatorNumeric, 533 String prevOperatorNumeric, boolean needToFixTimeZone) { 534 // Return false if the mcc isn't valid as we don't know where we are. 535 // Return true if we have an IccCard and the mcc changed or we 536 // need to fix it because when the NITZ time came in we didn't 537 // know the country code. 538 539 // If mcc is invalid then we'll return false 540 int mcc; 541 try { 542 mcc = Integer.parseInt(operatorNumeric.substring(0, 3)); 543 } catch (Exception e) { 544 if (DBG) { 545 log("shouldFixTimeZoneNow: no mcc, operatorNumeric=" + operatorNumeric + 546 " retVal=false"); 547 } 548 return false; 549 } 550 551 // If prevMcc is invalid will make it different from mcc 552 // so we'll return true if the card exists. 553 int prevMcc; 554 try { 555 prevMcc = Integer.parseInt(prevOperatorNumeric.substring(0, 3)); 556 } catch (Exception e) { 557 prevMcc = mcc + 1; 558 } 559 560 // Determine if the Icc card exists 561 IccCard iccCard = phoneBase.getIccCard(); 562 boolean iccCardExist = (iccCard != null) && iccCard.getState().iccCardExist(); 563 564 // Determine retVal 565 boolean retVal = ((iccCardExist && (mcc != prevMcc)) || needToFixTimeZone); 566 if (DBG) { 567 long ctm = System.currentTimeMillis(); 568 log("shouldFixTimeZoneNow: retVal=" + retVal + 569 " iccCard=" + iccCard + 570 " iccCard.state=" + (iccCard == null ? "null" : iccCard.getState().toString()) + 571 " iccCardExist=" + iccCardExist + 572 " operatorNumeric=" + operatorNumeric + " mcc=" + mcc + 573 " prevOperatorNumeric=" + prevOperatorNumeric + " prevMcc=" + prevMcc + 574 " needToFixTimeZone=" + needToFixTimeZone + 575 " ltod=" + TimeUtils.logTimeOfDay(ctm)); 576 } 577 return retVal; 578 } 579 580 /** 581 * @return all available cell information or null if none. 582 */ 583 public List<CellInfo> getAllCellInfo() { 584 return null; 585 } 586 587 /** 588 * @return signal strength 589 */ 590 public SignalStrength getSignalStrength() { 591 synchronized(mCellInfo) { 592 return mSignalStrength; 593 } 594 } 595 596 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 597 pw.println("ServiceStateTracker:"); 598 pw.println(" ss=" + ss); 599 pw.println(" newSS=" + newSS); 600 pw.println(" mCellInfo=" + mCellInfo); 601 pw.println(" mRestrictedState=" + mRestrictedState); 602 pw.println(" pollingContext=" + pollingContext); 603 pw.println(" mDesiredPowerState=" + mDesiredPowerState); 604 pw.println(" mRilRadioTechnology=" + mRilRadioTechnology); 605 pw.println(" mNewRilRadioTechnology=" + mNewRilRadioTechnology); 606 pw.println(" dontPollSignalStrength=" + dontPollSignalStrength); 607 pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff); 608 pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag); 609 } 610} 611