CdmaLteServiceStateTracker.java revision f92cb4bd5519427a0db673709d94683a8baf203a
1/* 2 * Copyright (C) 2012 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.telephony.CellInfo; 25import android.telephony.CellInfoLte; 26import android.telephony.CellSignalStrengthLte; 27import android.telephony.CellIdentityLte; 28import android.telephony.SignalStrength; 29import android.telephony.ServiceState; 30import android.telephony.cdma.CdmaCellLocation; 31import android.text.TextUtils; 32import android.os.AsyncResult; 33import android.os.Message; 34import android.os.SystemClock; 35import android.os.SystemProperties; 36 37import android.util.Log; 38import android.util.EventLog; 39 40import com.android.internal.telephony.IccCardApplicationStatus.AppState; 41import java.io.FileDescriptor; 42import java.io.PrintWriter; 43import java.util.ArrayList; 44import java.util.List; 45 46public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { 47 private CDMALTEPhone mCdmaLtePhone; 48 private final CellInfoLte mCellInfoLte; 49 50 private CellIdentityLte mNewCellIdentityLte = new CellIdentityLte(); 51 private CellIdentityLte mLasteCellIdentityLte = new CellIdentityLte(); 52 53 public CdmaLteServiceStateTracker(CDMALTEPhone phone) { 54 super(phone, new CellInfoLte()); 55 mCdmaLtePhone = phone; 56 mCellInfoLte = (CellInfoLte) mCellInfo; 57 58 ((CellInfoLte)mCellInfo).setCellSignalStrength(new CellSignalStrengthLte()); 59 ((CellInfoLte)mCellInfo).setCellIdentity(new CellIdentityLte()); 60 61 if (DBG) log("CdmaLteServiceStateTracker Constructors"); 62 } 63 64 @Override 65 public void handleMessage(Message msg) { 66 AsyncResult ar; 67 int[] ints; 68 String[] strings; 69 switch (msg.what) { 70 case EVENT_POLL_STATE_GPRS: 71 if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS"); 72 ar = (AsyncResult)msg.obj; 73 handlePollStateResult(msg.what, ar); 74 break; 75 case EVENT_RUIM_RECORDS_LOADED: 76 RuimRecords ruim = (RuimRecords)mIccRecords; 77 if ((ruim != null) && ruim.isProvisioned()) { 78 mMdn = ruim.getMdn(); 79 mMin = ruim.getMin(); 80 parseSidNid(ruim.getSid(), ruim.getNid()); 81 mPrlVersion = ruim.getPrlVersion();; 82 mIsMinInfoReady = true; 83 updateOtaspState(); 84 } 85 // SID/NID/PRL is loaded. Poll service state 86 // again to update to the roaming state with 87 // the latest variables. 88 pollState(); 89 break; 90 default: 91 super.handleMessage(msg); 92 } 93 } 94 95 /** 96 * Handle the result of one of the pollState()-related requests 97 */ 98 @Override 99 protected void handlePollStateResultMessage(int what, AsyncResult ar) { 100 if (what == EVENT_POLL_STATE_GPRS) { 101 String states[] = (String[])ar.result; 102 if (DBG) { 103 log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" + 104 states.length + " states=" + states); 105 } 106 107 int type = 0; 108 int regState = -1; 109 if (states.length > 0) { 110 try { 111 regState = Integer.parseInt(states[0]); 112 113 // states[3] (if present) is the current radio technology 114 if (states.length >= 4 && states[3] != null) { 115 type = Integer.parseInt(states[3]); 116 } 117 } catch (NumberFormatException ex) { 118 loge("handlePollStateResultMessage: error parsing GprsRegistrationState: " 119 + ex); 120 } 121 if (states.length >= 10) { 122 int mcc; 123 int mnc; 124 int tac; 125 int pci; 126 int eci; 127 int csgid; 128 String operatorNumeric = null; 129 130 try { 131 operatorNumeric = newSS.getOperatorNumeric(); 132 mcc = Integer.parseInt(operatorNumeric.substring(0,3)); 133 } catch (Exception e) { 134 try { 135 operatorNumeric = ss.getOperatorNumeric(); 136 mcc = Integer.parseInt(operatorNumeric.substring(0,3)); 137 } catch (Exception ex) { 138 loge("handlePollStateResultMessage: bad mcc operatorNumeric=" + 139 operatorNumeric + " ex=" + ex); 140 operatorNumeric = ""; 141 mcc = Integer.MAX_VALUE; 142 } 143 } 144 try { 145 mnc = Integer.parseInt(operatorNumeric.substring(3)); 146 } catch (Exception e) { 147 loge("handlePollStateResultMessage: bad mnc operatorNumeric=" + 148 operatorNumeric + " e=" + e); 149 mnc = Integer.MAX_VALUE; 150 } 151 try { 152 tac = Integer.parseInt(states[6], 16); 153 } catch (Exception e) { 154 loge("handlePollStateResultMessage: bad tac states[6]=" + 155 states[6] + " e=" + e); 156 tac = Integer.MAX_VALUE; 157 } 158 try { 159 pci = Integer.parseInt(states[7], 16); 160 } catch (Exception e) { 161 loge("handlePollStateResultMessage: bad pci states[7]=" + 162 states[7] + " e=" + e); 163 pci = Integer.MAX_VALUE; 164 } 165 try { 166 eci = Integer.parseInt(states[8], 16); 167 } catch (Exception e) { 168 loge("handlePollStateResultMessage: bad eci states[8]=" + 169 states[8] + " e=" + e); 170 eci = Integer.MAX_VALUE; 171 } 172 try { 173 csgid = Integer.parseInt(states[9], 16); 174 } catch (Exception e) { 175 // FIX: Always bad so don't pollute the logs 176 // loge("handlePollStateResultMessage: bad csgid states[9]=" + 177 // states[9] + " e=" + e); 178 csgid = Integer.MAX_VALUE; 179 } 180 mNewCellIdentityLte = new CellIdentityLte(mcc, mnc, eci, pci, tac); 181 if (DBG) { 182 log("handlePollStateResultMessage: mNewLteCellIdentity=" + 183 mNewCellIdentityLte); 184 } 185 } 186 } 187 188 newSS.setRilDataRadioTechnology(type); 189 int dataRegState = regCodeToServiceState(regState); 190 newSS.setDataRegState(dataRegState); 191 if (DBG) { 192 log("handlPollStateResultMessage: CdmaLteSST setDataRegState=" + dataRegState 193 + " regState=" + regState 194 + " dataRadioTechnology=" + type); 195 } 196 } else { 197 super.handlePollStateResultMessage(what, ar); 198 } 199 } 200 201 @Override 202 protected void pollState() { 203 pollingContext = new int[1]; 204 pollingContext[0] = 0; 205 206 switch (cm.getRadioState()) { 207 case RADIO_UNAVAILABLE: 208 newSS.setStateOutOfService(); 209 newCellLoc.setStateInvalid(); 210 setSignalStrengthDefaultValues(); 211 mGotCountryCode = false; 212 213 pollStateDone(); 214 break; 215 216 case RADIO_OFF: 217 newSS.setStateOff(); 218 newCellLoc.setStateInvalid(); 219 setSignalStrengthDefaultValues(); 220 mGotCountryCode = false; 221 222 pollStateDone(); 223 break; 224 225 default: 226 // Issue all poll-related commands at once, then count 227 // down the responses which are allowed to arrive 228 // out-of-order. 229 230 pollingContext[0]++; 231 // RIL_REQUEST_OPERATOR is necessary for CDMA 232 cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); 233 234 pollingContext[0]++; 235 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA 236 cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, 237 pollingContext)); 238 239 pollingContext[0]++; 240 // RIL_REQUEST_DATA_REGISTRATION_STATE 241 cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, 242 pollingContext)); 243 break; 244 } 245 } 246 247 @Override 248 protected void pollStateDone() { 249 log("pollStateDone: lte 1 ss=[" + ss + "] newSS=[" + newSS + "]"); 250 251 boolean hasRegistered = ss.getVoiceRegState() != ServiceState.STATE_IN_SERVICE 252 && newSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 253 254 boolean hasDeregistered = ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE 255 && newSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; 256 257 boolean hasCdmaDataConnectionAttached = 258 ss.getDataRegState() != ServiceState.STATE_IN_SERVICE 259 && newSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; 260 261 boolean hasCdmaDataConnectionDetached = 262 ss.getDataRegState() == ServiceState.STATE_IN_SERVICE 263 && newSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; 264 265 boolean hasCdmaDataConnectionChanged = 266 ss.getDataRegState() != newSS.getDataRegState(); 267 268 boolean hasVoiceRadioTechnologyChanged = ss.getRilVoiceRadioTechnology() 269 != newSS.getRilVoiceRadioTechnology(); 270 271 boolean hasDataRadioTechnologyChanged = ss.getRilDataRadioTechnology() 272 != newSS.getRilDataRadioTechnology(); 273 274 boolean hasChanged = !newSS.equals(ss); 275 276 boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming(); 277 278 boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming(); 279 280 boolean hasLocationChanged = !newCellLoc.equals(cellLoc); 281 282 boolean has4gHandoff = 283 newSS.getDataRegState() == ServiceState.STATE_IN_SERVICE && 284 (((ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && 285 (newSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) || 286 ((ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD) && 287 (newSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE))); 288 289 boolean hasMultiApnSupport = 290 (((newSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) || 291 (newSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) && 292 ((ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && 293 (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD))); 294 295 boolean hasLostMultiApnSupport = 296 ((newSS.getRilDataRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A) && 297 (newSS.getRilDataRadioTechnology() <= ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)); 298 299 if (DBG) { 300 log("pollStateDone:" 301 + " hasRegistered=" + hasRegistered 302 + " hasDeegistered=" + hasDeregistered 303 + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached 304 + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached 305 + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged 306 + " hasVoiceRadioTechnologyChanged= " + hasVoiceRadioTechnologyChanged 307 + " hasDataRadioTechnologyChanged=" + hasDataRadioTechnologyChanged 308 + " hasChanged=" + hasChanged 309 + " hasRoamingOn=" + hasRoamingOn 310 + " hasRoamingOff=" + hasRoamingOff 311 + " hasLocationChanged=" + hasLocationChanged 312 + " has4gHandoff = " + has4gHandoff 313 + " hasMultiApnSupport=" + hasMultiApnSupport 314 + " hasLostMultiApnSupport=" + hasLostMultiApnSupport); 315 } 316 // Add an event log when connection state changes 317 if (ss.getVoiceRegState() != newSS.getVoiceRegState() 318 || ss.getDataRegState() != newSS.getDataRegState()) { 319 EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getVoiceRegState(), 320 ss.getDataRegState(), newSS.getVoiceRegState(), newSS.getDataRegState()); 321 } 322 323 ServiceState tss; 324 tss = ss; 325 ss = newSS; 326 newSS = tss; 327 // clean slate for next time 328 newSS.setStateOutOfService(); 329 330 CdmaCellLocation tcl = cellLoc; 331 cellLoc = newCellLoc; 332 newCellLoc = tcl; 333 334 newSS.setStateOutOfService(); // clean slate for next time 335 336 if (hasVoiceRadioTechnologyChanged) { 337 phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 338 ServiceState.rilRadioTechnologyToString(ss.getRilDataRadioTechnology())); 339 } 340 341 if (hasRegistered) { 342 mNetworkAttachedRegistrants.notifyRegistrants(); 343 } 344 345 if (hasChanged) { 346 if (phone.isEriFileLoaded()) { 347 String eriText; 348 // Now the CDMAPhone sees the new ServiceState so it can get the 349 // new ERI text 350 if (ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { 351 eriText = phone.getCdmaEriText(); 352 } else if (ss.getVoiceRegState() == ServiceState.STATE_POWER_OFF) { 353 eriText = (mIccRecords != null) ? mIccRecords.getServiceProviderName() : null; 354 if (TextUtils.isEmpty(eriText)) { 355 // Sets operator alpha property by retrieving from 356 // build-time system property 357 eriText = SystemProperties.get("ro.cdma.home.operator.alpha"); 358 } 359 } else { 360 // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used 361 // for mRegistrationState 0,2,3 and 4 362 eriText = phone.getContext() 363 .getText(com.android.internal.R.string.roamingTextSearching).toString(); 364 } 365 ss.setOperatorAlphaLong(eriText); 366 } 367 368 if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY && 369 mIccRecords != null) { 370 // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches 371 // one configured in SIM, use operator name from CSIM record. 372 boolean showSpn = 373 ((RuimRecords)mIccRecords).getCsimSpnDisplayCondition(); 374 int iconIndex = ss.getCdmaEriIconIndex(); 375 376 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) && 377 isInHomeSidNid(ss.getSystemId(), ss.getNetworkId()) && 378 mIccRecords != null) { 379 ss.setOperatorAlphaLong(mIccRecords.getServiceProviderName()); 380 } 381 } 382 383 String operatorNumeric; 384 385 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 386 ss.getOperatorAlphaLong()); 387 388 String prevOperatorNumeric = 389 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); 390 operatorNumeric = ss.getOperatorNumeric(); 391 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 392 393 if (operatorNumeric == null) { 394 if (DBG) log("operatorNumeric is null"); 395 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 396 mGotCountryCode = false; 397 } else { 398 String isoCountryCode = ""; 399 String mcc = operatorNumeric.substring(0, 3); 400 try { 401 isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric 402 .substring(0, 3))); 403 } catch (NumberFormatException ex) { 404 loge("countryCodeForMcc error" + ex); 405 } catch (StringIndexOutOfBoundsException ex) { 406 loge("countryCodeForMcc error" + ex); 407 } 408 409 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, 410 isoCountryCode); 411 mGotCountryCode = true; 412 413 if (shouldFixTimeZoneNow(phone, operatorNumeric, prevOperatorNumeric, 414 mNeedFixZone)) { 415 fixTimeZone(isoCountryCode); 416 } 417 } 418 419 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 420 ss.getRoaming() ? "true" : "false"); 421 422 updateSpnDisplay(); 423 phone.notifyServiceStateChanged(ss); 424 } 425 426 if (hasCdmaDataConnectionAttached || has4gHandoff) { 427 mAttachedRegistrants.notifyRegistrants(); 428 } 429 430 if (hasCdmaDataConnectionDetached) { 431 mDetachedRegistrants.notifyRegistrants(); 432 } 433 434 if ((hasCdmaDataConnectionChanged || hasDataRadioTechnologyChanged)) { 435 log("pollStateDone: call notifyDataConnection"); 436 phone.notifyDataConnection(null); 437 } 438 439 if (hasRoamingOn) { 440 mRoamingOnRegistrants.notifyRegistrants(); 441 } 442 443 if (hasRoamingOff) { 444 mRoamingOffRegistrants.notifyRegistrants(); 445 } 446 447 if (hasLocationChanged) { 448 phone.notifyLocationChanged(); 449 } 450 451 ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>(); 452 synchronized(mCellInfo) { 453 CellInfoLte cil = (CellInfoLte)mCellInfo; 454 455 boolean cidChanged = ! mNewCellIdentityLte.equals(mLasteCellIdentityLte); 456 if (hasRegistered || hasDeregistered || cidChanged) { 457 // TODO: Handle the absence of LteCellIdentity 458 long timeStamp = SystemClock.elapsedRealtime() * 1000; 459 boolean registered = ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 460 mLasteCellIdentityLte = mNewCellIdentityLte; 461 462 cil.setRegisterd(registered); 463 cil.setCellIdentity(mLasteCellIdentityLte); 464 if (DBG) { 465 log("pollStateDone: hasRegistered=" + hasRegistered + 466 " hasDeregistered=" + hasDeregistered + 467 " cidChanged=" + cidChanged + 468 " mCellInfo=" + mCellInfo); 469 } 470 arrayCi.add(mCellInfo); 471 } 472 mPhoneBase.notifyCellInfo(arrayCi); 473 } 474 } 475 476 @Override 477 protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) { 478 if (ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 479 isGsm = true; 480 } 481 boolean ssChanged = super.onSignalStrengthResult(ar, isGsm); 482 483 synchronized (mCellInfo) { 484 if (ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 485 mCellInfoLte.setTimeStamp(SystemClock.elapsedRealtime() * 1000); 486 mCellInfoLte.setTimeStampType(CellInfo.TIMESTAMP_TYPE_JAVA_RIL); 487 mCellInfoLte.getCellSignalStrength() 488 .initialize(mSignalStrength,SignalStrength.INVALID); 489 } 490 if (mCellInfoLte.getCellIdentity() != null) { 491 ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>(); 492 arrayCi.add(mCellInfoLte); 493 mPhoneBase.notifyCellInfo(arrayCi); 494 } 495 } 496 return ssChanged; 497 } 498 499 @Override 500 public boolean isConcurrentVoiceAndDataAllowed() { 501 // Note: it needs to be confirmed which CDMA network types 502 // can support voice and data calls concurrently. 503 // For the time-being, the return value will be false. 504 return (ss.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE); 505 } 506 507 /** 508 * Check whether the specified SID and NID pair appears in the HOME SID/NID list 509 * read from NV or SIM. 510 * 511 * @return true if provided sid/nid pair belongs to operator's home network. 512 */ 513 private boolean isInHomeSidNid(int sid, int nid) { 514 // if SID/NID is not available, assume this is home network. 515 if (isSidsAllZeros()) return true; 516 517 // length of SID/NID shold be same 518 if (mHomeSystemId.length != mHomeNetworkId.length) return true; 519 520 if (sid == 0) return true; 521 522 for (int i = 0; i < mHomeSystemId.length; i++) { 523 // Use SID only if NID is a reserved value. 524 // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2) 525 if ((mHomeSystemId[i] == sid) && 526 ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) || 527 (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) { 528 return true; 529 } 530 } 531 // SID/NID are not in the list. So device is not in home network 532 return false; 533 } 534 535 /** 536 * @return all available cell information, the returned List maybe empty but never null. 537 */ 538 @Override 539 public List<CellInfo> getAllCellInfo() { 540 ArrayList<CellInfo> arrayList = new ArrayList<CellInfo>(); 541 CellInfo ci; 542 synchronized(mCellInfo) { 543 arrayList.add(mCellInfoLte); 544 } 545 if (DBG) log ("getAllCellInfo: arrayList=" + arrayList); 546 return arrayList; 547 } 548 549 @Override 550 protected void log(String s) { 551 Log.d(LOG_TAG, "[CdmaLteSST] " + s); 552 } 553 554 @Override 555 protected void loge(String s) { 556 Log.e(LOG_TAG, "[CdmaLteSST] " + s); 557 } 558 559 @Override 560 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 561 pw.println("CdmaLteServiceStateTracker extends:"); 562 super.dump(fd, pw, args); 563 pw.println(" mCdmaLtePhone=" + mCdmaLtePhone); 564 } 565} 566