CdmaLteServiceStateTracker.java revision 5e39519396918f9e2312d1c355a9b6889851d887
1/* 2 * Copyright (C) 2008 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.cdma; 18 19import com.android.internal.telephony.TelephonyProperties; 20import com.android.internal.telephony.MccTable; 21import com.android.internal.telephony.EventLogTags; 22import com.android.internal.telephony.RILConstants; 23 24import android.content.Intent; 25import android.telephony.SignalStrength; 26import android.telephony.ServiceState; 27import android.telephony.cdma.CdmaCellLocation; 28import android.os.AsyncResult; 29import android.os.Message; 30import android.provider.Telephony.Intents; 31 32import android.text.TextUtils; 33import android.util.Log; 34import android.util.EventLog; 35 36import com.android.internal.telephony.gsm.GsmDataConnectionTracker; 37 38public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { 39 CDMALTEPhone mCdmaLtePhone; 40 41 private ServiceState mLteSS; // The last LTE state from Voice Registration 42 private boolean mNeedToRegForSimLoaded = true; 43 44 public CdmaLteServiceStateTracker(CDMALTEPhone phone) { 45 super(phone); 46 cm.registerForSIMReady(this, EVENT_SIM_READY, null); 47 mCdmaLtePhone = phone; 48 49 mLteSS = new ServiceState(); 50 if (DBG) log("CdmaLteServiceStateTracker Constructors"); 51 } 52 53 @Override 54 public void dispose() { 55 cm.unregisterForSIMReady(this); 56 super.dispose(); 57 } 58 59 @Override 60 public void handleMessage(Message msg) { 61 AsyncResult ar; 62 int[] ints; 63 String[] strings; 64 switch (msg.what) { 65 case EVENT_POLL_STATE_GPRS: 66 if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS"); 67 ar = (AsyncResult)msg.obj; 68 handlePollStateResult(msg.what, ar); 69 break; 70 case EVENT_SIM_READY: 71 if (DBG) log("handleMessage EVENT_SIM_READY"); 72 isSubscriptionFromRuim = false; 73 // Register SIM_RECORDS_LOADED dynamically. 74 // This is to avoid confilct with RUIM_READY scenario) 75 if (mNeedToRegForSimLoaded) { 76 phone.mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); 77 mNeedToRegForSimLoaded = false; 78 } 79 pollState(); 80 // Signal strength polling stops when radio is off. 81 queueNextSignalStrengthPoll(); 82 83 // load ERI file 84 phone.prepareEri(); 85 break; 86 case EVENT_SIM_RECORDS_LOADED: 87 CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords; 88 if ((sim != null) && sim.isProvisioned()) { 89 mMdn = sim.getMdn(); 90 mMin = sim.getMin(); 91 parseSidNid(sim.getSid(), sim.getNid()); 92 mPrlVersion = sim.getPrlVersion();; 93 mIsMinInfoReady = true; 94 updateOtaspState(); 95 } 96 // SID/NID/PRL is loaded. Poll service state 97 // again to update to the roaming state with 98 // the latest variables. 99 pollState(); 100 break; 101 default: 102 super.handleMessage(msg); 103 } 104 } 105 106 /** 107 * Set the cdmaSS for EVENT_POLL_STATE_REGISTRATION_CDMA 108 */ 109 @Override 110 protected void setCdmaTechnology(int radioTechnology) { 111 // Called on voice registration state response. 112 // Just record new CDMA radio technology 113 newSS.setRadioTechnology(radioTechnology); 114 } 115 116 /** 117 * Handle the result of one of the pollState()-related requests 118 */ 119 @Override 120 protected void handlePollStateResultMessage(int what, AsyncResult ar) { 121 if (what == EVENT_POLL_STATE_GPRS) { 122 if (DBG) log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS"); 123 String states[] = (String[])ar.result; 124 125 int type = 0; 126 int regState = -1; 127 if (states.length > 0) { 128 try { 129 regState = Integer.parseInt(states[0]); 130 131 // states[3] (if present) is the current radio technology 132 if (states.length >= 4 && states[3] != null) { 133 type = Integer.parseInt(states[3]); 134 } 135 } catch (NumberFormatException ex) { 136 loge("handlePollStateResultMessage: error parsing GprsRegistrationState: " 137 + ex); 138 } 139 } 140 141 mLteSS.setRadioTechnology(type); 142 mLteSS.setState(regCodeToServiceState(regState)); 143 } else { 144 super.handlePollStateResultMessage(what, ar); 145 } 146 } 147 148 @Override 149 protected void setSignalStrengthDefaultValues() { 150 // TODO Make a constructor only has boolean gsm as parameter 151 mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, 152 -1, -1, -1, SignalStrength.INVALID_SNR, -1, false); 153 } 154 155 @Override 156 protected void pollState() { 157 pollingContext = new int[1]; 158 pollingContext[0] = 0; 159 160 switch (cm.getRadioState()) { 161 case RADIO_UNAVAILABLE: 162 newSS.setStateOutOfService(); 163 newCellLoc.setStateInvalid(); 164 setSignalStrengthDefaultValues(); 165 mGotCountryCode = false; 166 167 pollStateDone(); 168 break; 169 170 case RADIO_OFF: 171 newSS.setStateOff(); 172 newCellLoc.setStateInvalid(); 173 setSignalStrengthDefaultValues(); 174 mGotCountryCode = false; 175 176 pollStateDone(); 177 break; 178 179 default: 180 // Issue all poll-related commands at once, then count 181 // down the responses which are allowed to arrive 182 // out-of-order. 183 184 pollingContext[0]++; 185 // RIL_REQUEST_OPERATOR is necessary for CDMA 186 cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); 187 188 pollingContext[0]++; 189 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA 190 cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, 191 pollingContext)); 192 193 int networkMode = android.provider.Settings.Secure.getInt(phone.getContext() 194 .getContentResolver(), 195 android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, 196 RILConstants.PREFERRED_NETWORK_MODE); 197 if (DBG) log("pollState: network mode here is = " + networkMode); 198 if ((networkMode == RILConstants.NETWORK_MODE_GLOBAL) 199 || (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY)) { 200 pollingContext[0]++; 201 // RIL_REQUEST_DATA_REGISTRATION_STATE 202 cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, 203 pollingContext)); 204 } 205 break; 206 } 207 } 208 209 @Override 210 protected void pollStateDone() { 211 // determine data NetworkType from both LET and CDMA SS 212 if (mLteSS.getState() == ServiceState.STATE_IN_SERVICE) { 213 //in LTE service 214 newNetworkType = mLteSS.getRadioTechnology(); 215 mNewDataConnectionState = mLteSS.getState(); 216 newSS.setRadioTechnology(newNetworkType); 217 log("pollStateDone LTE/eHRPD STATE_IN_SERVICE newNetworkType = " + newNetworkType); 218 } else { 219 // LTE out of service, get CDMA Service State 220 newNetworkType = newSS.getRadioTechnology(); 221 mNewDataConnectionState = radioTechnologyToDataServiceState(newNetworkType); 222 log("pollStateDone CDMA STATE_IN_SERVICE newNetworkType = " + newNetworkType + 223 " mNewDataConnectionState = " + mNewDataConnectionState); 224 } 225 226 // TODO: Add proper support for LTE Only, we should be looking at 227 // the preferred network mode, to know when newSS state should 228 // be coming from mLteSs state. This was needed to pass a VZW 229 // LTE Only test. 230 // 231 // If CDMA service is OOS, double check if the device is running with LTE only 232 // mode. If that is the case, derive the service state from LTE side. 233 // To set in LTE only mode, sqlite3 /data/data/com.android.providers.settings/ 234 // databases/settings.db "update secure set value='11' where name='preferred_network_mode'" 235 if (newSS.getState() == ServiceState.STATE_OUT_OF_SERVICE) { 236 int networkMode = android.provider.Settings.Secure.getInt(phone.getContext() 237 .getContentResolver(), 238 android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, 239 RILConstants.PREFERRED_NETWORK_MODE); 240 if (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY) { 241 if (DBG) log("pollState: LTE Only mode"); 242 newSS.setState(mLteSS.getState()); 243 } 244 } 245 246 if (DBG) log("pollStateDone: oldSS=[" + ss + "] newSS=[" + newSS + "]"); 247 248 boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE 249 && newSS.getState() == ServiceState.STATE_IN_SERVICE; 250 251 boolean hasDeregistered = ss.getState() == ServiceState.STATE_IN_SERVICE 252 && newSS.getState() != ServiceState.STATE_IN_SERVICE; 253 254 boolean hasCdmaDataConnectionAttached = 255 mDataConnectionState != ServiceState.STATE_IN_SERVICE 256 && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE; 257 258 boolean hasCdmaDataConnectionDetached = 259 mDataConnectionState == ServiceState.STATE_IN_SERVICE 260 && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE; 261 262 boolean hasCdmaDataConnectionChanged = 263 mDataConnectionState != mNewDataConnectionState; 264 265 boolean hasNetworkTypeChanged = networkType != newNetworkType; 266 267 boolean hasChanged = !newSS.equals(ss); 268 269 boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming(); 270 271 boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming(); 272 273 boolean hasLocationChanged = !newCellLoc.equals(cellLoc); 274 275 boolean has4gHandoff = 276 mNewDataConnectionState == ServiceState.STATE_IN_SERVICE && 277 (((networkType == ServiceState.RADIO_TECHNOLOGY_LTE) && 278 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) || 279 ((networkType == ServiceState.RADIO_TECHNOLOGY_EHRPD) && 280 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE))); 281 282 boolean hasMultiApnSupport = 283 (((newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE) || 284 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) && 285 ((networkType != ServiceState.RADIO_TECHNOLOGY_LTE) && 286 (networkType != ServiceState.RADIO_TECHNOLOGY_EHRPD))); 287 288 boolean hasLostMultiApnSupport = 289 ((newNetworkType >= ServiceState.RADIO_TECHNOLOGY_IS95A) && 290 (newNetworkType <= ServiceState.RADIO_TECHNOLOGY_EVDO_A)); 291 292 if (DBG) { 293 log("pollStateDone:" 294 + " hasRegistered=" + hasRegistered 295 + " hasDeegistered=" + hasDeregistered 296 + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached 297 + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached 298 + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged 299 + " hasNetworkTypeChanged = " + hasNetworkTypeChanged 300 + " hasChanged=" + hasChanged 301 + " hasRoamingOn=" + hasRoamingOn 302 + " hasRoamingOff=" + hasRoamingOff 303 + " hasLocationChanged=" + hasLocationChanged 304 + " has4gHandoff = " + has4gHandoff 305 + " hasMultiApnSupport=" + hasMultiApnSupport 306 + " hasLostMultiApnSupport=" + hasLostMultiApnSupport); 307 } 308 // Add an event log when connection state changes 309 if (ss.getState() != newSS.getState() 310 || mDataConnectionState != mNewDataConnectionState) { 311 EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(), 312 mDataConnectionState, newSS.getState(), mNewDataConnectionState); 313 } 314 315 ServiceState tss; 316 tss = ss; 317 ss = newSS; 318 newSS = tss; 319 // clean slate for next time 320 newSS.setStateOutOfService(); 321 mLteSS.setStateOutOfService(); 322 323 if ((hasMultiApnSupport) 324 && (phone.mDataConnectionTracker instanceof CdmaDataConnectionTracker)) { 325 if (DBG) log("GsmDataConnectionTracker Created"); 326 phone.mDataConnectionTracker.dispose(); 327 phone.mDataConnectionTracker = new GsmDataConnectionTracker(mCdmaLtePhone); 328 } 329 330 if ((hasLostMultiApnSupport) 331 && (phone.mDataConnectionTracker instanceof GsmDataConnectionTracker)) { 332 if (DBG)log("GsmDataConnectionTracker disposed"); 333 phone.mDataConnectionTracker.dispose(); 334 phone.mDataConnectionTracker = new CdmaDataConnectionTracker(phone); 335 } 336 337 CdmaCellLocation tcl = cellLoc; 338 cellLoc = newCellLoc; 339 newCellLoc = tcl; 340 341 mDataConnectionState = mNewDataConnectionState; 342 networkType = newNetworkType; 343 344 newSS.setStateOutOfService(); // clean slate for next time 345 346 if (hasNetworkTypeChanged) { 347 phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 348 ServiceState.radioTechnologyToString(networkType)); 349 } 350 351 if (hasRegistered) { 352 mNetworkAttachedRegistrants.notifyRegistrants(); 353 } 354 355 if (hasChanged) { 356 if (phone.isEriFileLoaded()) { 357 String eriText; 358 // Now the CDMAPhone sees the new ServiceState so it can get the 359 // new ERI text 360 if (ss.getState() == ServiceState.STATE_IN_SERVICE) { 361 eriText = phone.getCdmaEriText(); 362 } else { 363 // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used 364 // for 365 // mRegistrationState 0,2,3 and 4 366 eriText = phone.getContext() 367 .getText(com.android.internal.R.string.roamingTextSearching).toString(); 368 } 369 ss.setOperatorAlphaLong(eriText); 370 } 371 372 if (cm.getSimState().isSIMReady()) { 373 // SIM is found on the device. If ERI roaming is OFF and SID/NID matches 374 // one configfured in SIM, use operator name from CSIM record. 375 boolean showSpn = 376 ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition(); 377 int iconIndex = ss.getCdmaEriIconIndex(); 378 379 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) && 380 isInHomeSidNid(ss.getSystemId(), ss.getNetworkId())) { 381 ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName()); 382 } 383 } 384 385 String operatorNumeric; 386 387 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 388 ss.getOperatorAlphaLong()); 389 390 operatorNumeric = ss.getOperatorNumeric(); 391 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 392 393 if (operatorNumeric == null) { 394 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 395 mGotCountryCode = false; 396 } else { 397 String isoCountryCode = ""; 398 try { 399 isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric 400 .substring(0, 3))); 401 } catch (NumberFormatException ex) { 402 loge("countryCodeForMcc error" + ex); 403 } catch (StringIndexOutOfBoundsException ex) { 404 loge("countryCodeForMcc error" + ex); 405 } 406 407 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, 408 isoCountryCode); 409 mGotCountryCode = true; 410 if (mNeedFixZone) { 411 fixTimeZone(isoCountryCode); 412 } 413 } 414 415 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 416 ss.getRoaming() ? "true" : "false"); 417 418 updateSpnDisplay(); 419 phone.notifyServiceStateChanged(ss); 420 } 421 422 if (hasCdmaDataConnectionAttached || has4gHandoff) { 423 mAttachedRegistrants.notifyRegistrants(); 424 } 425 426 if (hasCdmaDataConnectionDetached) { 427 mDetachedRegistrants.notifyRegistrants(); 428 } 429 430 if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)) { 431 phone.notifyDataConnection(null); 432 } 433 434 if (hasRoamingOn) { 435 mRoamingOnRegistrants.notifyRegistrants(); 436 } 437 438 if (hasRoamingOff) { 439 mRoamingOffRegistrants.notifyRegistrants(); 440 } 441 442 if (hasLocationChanged) { 443 phone.notifyLocationChanged(); 444 } 445 } 446 447 @Override 448 protected void onSignalStrengthResult(AsyncResult ar) { 449 SignalStrength oldSignalStrength = mSignalStrength; 450 451 if (ar.exception != null) { 452 // Most likely radio is resetting/disconnected change to default 453 // values. 454 setSignalStrengthDefaultValues(); 455 } else { 456 int[] ints = (int[])ar.result; 457 458 int lteRssi = -1; 459 int lteRsrp = -1; 460 int lteRsrq = -1; 461 int lteRssnr = SignalStrength.INVALID_SNR; 462 int lteCqi = -1; 463 464 int offset = 2; 465 int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120; 466 int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160; 467 int evdoRssi = (ints[offset + 2] > 0) ? -ints[offset + 2] : -120; 468 int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1; 469 int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4] 470 : -1; 471 472 if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) { 473 lteRssi = ints[offset+5]; 474 lteRsrp = ints[offset+6]; 475 lteRsrq = ints[offset+7]; 476 lteRssnr = ints[offset+8]; 477 lteCqi = ints[offset+9]; 478 } 479 480 if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) { 481 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio, 482 evdoSnr, false); 483 } else { 484 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio, 485 evdoSnr, lteRssi, lteRsrp, lteRsrq, lteRssnr, lteCqi, true); 486 } 487 } 488 489 try { 490 phone.notifySignalStrength(); 491 } catch (NullPointerException ex) { 492 loge("onSignalStrengthResult() Phone already destroyed: " + ex 493 + "SignalStrength not notified"); 494 } 495 } 496 497 @Override 498 public boolean isConcurrentVoiceAndDataAllowed() { 499 // Note: it needs to be confirmed which CDMA network types 500 // can support voice and data calls concurrently. 501 // For the time-being, the return value will be false. 502 return (networkType == ServiceState.RADIO_TECHNOLOGY_LTE); 503 } 504 505 /** 506 * Check whether the specified SID and NID pair appears in the HOME SID/NID list 507 * read from NV or SIM. 508 * 509 * @return true if provided sid/nid pair belongs to operator's home network. 510 */ 511 private boolean isInHomeSidNid(int sid, int nid) { 512 // if SID/NID is not available, assume this is home network. 513 if (isSidsAllZeros()) return true; 514 515 // length of SID/NID shold be same 516 if (mHomeSystemId.length != mHomeNetworkId.length) return true; 517 518 if (sid == 0) return true; 519 520 for (int i = 0; i < mHomeSystemId.length; i++) { 521 // Use SID only if NID is a reserved value. 522 // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2) 523 if ((mHomeSystemId[i] == sid) && 524 ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) || 525 (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) { 526 return true; 527 } 528 } 529 // SID/NID are not in the list. So device is not in home network 530 return false; 531 } 532 533 @Override 534 protected void log(String s) { 535 Log.d(LOG_TAG, "[CdmaLteSST] " + s); 536 } 537 538 @Override 539 protected void loge(String s) { 540 Log.e(LOG_TAG, "[CdmaLteSST] " + s); 541 } 542} 543