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 17 package com.android.internal.telephony.cdma; 18 19 import com.android.internal.telephony.TelephonyProperties; 20 import com.android.internal.telephony.MccTable; 21 import com.android.internal.telephony.EventLogTags; 22 import com.android.internal.telephony.uicc.RuimRecords; 23 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; 24 25 import android.telephony.CellInfo; 26 import android.telephony.CellInfoLte; 27 import android.telephony.CellSignalStrengthLte; 28 import android.telephony.CellIdentityLte; 29 import android.telephony.SignalStrength; 30 import android.telephony.ServiceState; 31 import android.telephony.cdma.CdmaCellLocation; 32 import android.text.TextUtils; 33 import android.os.AsyncResult; 34 import android.os.Message; 35 import android.os.SystemClock; 36 import android.os.SystemProperties; 37 38 import android.telephony.Rlog; 39 import android.util.EventLog; 40 41 import java.io.FileDescriptor; 42 import java.io.PrintWriter; 43 import java.util.ArrayList; 44 import java.util.List; 45 46 public 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 = mNewSS.getOperatorNumeric(); 132 mcc = Integer.parseInt(operatorNumeric.substring(0,3)); 133 } catch (Exception e) { 134 try { 135 operatorNumeric = mSS.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 152 // Use Integer#decode to be generous in what we receive and allow 153 // decimal, hex or octal values. 154 try { 155 tac = Integer.decode(states[6]); 156 } catch (Exception e) { 157 loge("handlePollStateResultMessage: bad tac states[6]=" + 158 states[6] + " e=" + e); 159 tac = Integer.MAX_VALUE; 160 } 161 try { 162 pci = Integer.decode(states[7]); 163 } catch (Exception e) { 164 loge("handlePollStateResultMessage: bad pci states[7]=" + 165 states[7] + " e=" + e); 166 pci = Integer.MAX_VALUE; 167 } 168 try { 169 eci = Integer.decode(states[8]); 170 } catch (Exception e) { 171 loge("handlePollStateResultMessage: bad eci states[8]=" + 172 states[8] + " e=" + e); 173 eci = Integer.MAX_VALUE; 174 } 175 try { 176 csgid = Integer.decode(states[9]); 177 } catch (Exception e) { 178 // FIX: Always bad so don't pollute the logs 179 // loge("handlePollStateResultMessage: bad csgid states[9]=" + 180 // states[9] + " e=" + e); 181 csgid = Integer.MAX_VALUE; 182 } 183 mNewCellIdentityLte = new CellIdentityLte(mcc, mnc, eci, pci, tac); 184 if (DBG) { 185 log("handlePollStateResultMessage: mNewLteCellIdentity=" + 186 mNewCellIdentityLte); 187 } 188 } 189 } 190 191 mNewSS.setRilDataRadioTechnology(type); 192 int dataRegState = regCodeToServiceState(regState); 193 mNewSS.setDataRegState(dataRegState); 194 if (DBG) { 195 log("handlPollStateResultMessage: CdmaLteSST setDataRegState=" + dataRegState 196 + " regState=" + regState 197 + " dataRadioTechnology=" + type); 198 } 199 } else { 200 super.handlePollStateResultMessage(what, ar); 201 } 202 } 203 204 @Override 205 protected void pollState() { 206 mPollingContext = new int[1]; 207 mPollingContext[0] = 0; 208 209 switch (mCi.getRadioState()) { 210 case RADIO_UNAVAILABLE: 211 mNewSS.setStateOutOfService(); 212 mNewCellLoc.setStateInvalid(); 213 setSignalStrengthDefaultValues(); 214 mGotCountryCode = false; 215 216 pollStateDone(); 217 break; 218 219 case RADIO_OFF: 220 mNewSS.setStateOff(); 221 mNewCellLoc.setStateInvalid(); 222 setSignalStrengthDefaultValues(); 223 mGotCountryCode = false; 224 225 pollStateDone(); 226 break; 227 228 default: 229 // Issue all poll-related commands at once, then count 230 // down the responses which are allowed to arrive 231 // out-of-order. 232 233 mPollingContext[0]++; 234 // RIL_REQUEST_OPERATOR is necessary for CDMA 235 mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, mPollingContext)); 236 237 mPollingContext[0]++; 238 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA 239 mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, 240 mPollingContext)); 241 242 mPollingContext[0]++; 243 // RIL_REQUEST_DATA_REGISTRATION_STATE 244 mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, 245 mPollingContext)); 246 break; 247 } 248 } 249 250 @Override 251 protected void pollStateDone() { 252 log("pollStateDone: lte 1 ss=[" + mSS + "] newSS=[" + mNewSS + "]"); 253 254 useDataRegStateForDataOnlyDevices(); 255 256 boolean hasRegistered = mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE 257 && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 258 259 boolean hasDeregistered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE 260 && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; 261 262 boolean hasCdmaDataConnectionAttached = 263 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE 264 && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; 265 266 boolean hasCdmaDataConnectionDetached = 267 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE 268 && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; 269 270 boolean hasCdmaDataConnectionChanged = 271 mSS.getDataRegState() != mNewSS.getDataRegState(); 272 273 boolean hasVoiceRadioTechnologyChanged = mSS.getRilVoiceRadioTechnology() 274 != mNewSS.getRilVoiceRadioTechnology(); 275 276 boolean hasDataRadioTechnologyChanged = mSS.getRilDataRadioTechnology() 277 != mNewSS.getRilDataRadioTechnology(); 278 279 boolean hasChanged = !mNewSS.equals(mSS); 280 281 boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming(); 282 283 boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming(); 284 285 boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc); 286 287 boolean has4gHandoff = 288 mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE && 289 (((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && 290 (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) || 291 ((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD) && 292 (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE))); 293 294 boolean hasMultiApnSupport = 295 (((mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) || 296 (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) && 297 ((mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && 298 (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD))); 299 300 boolean hasLostMultiApnSupport = 301 ((mNewSS.getRilDataRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A) && 302 (mNewSS.getRilDataRadioTechnology() <= ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)); 303 304 if (DBG) { 305 log("pollStateDone:" 306 + " hasRegistered=" + hasRegistered 307 + " hasDeegistered=" + hasDeregistered 308 + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached 309 + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached 310 + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged 311 + " hasVoiceRadioTechnologyChanged= " + hasVoiceRadioTechnologyChanged 312 + " hasDataRadioTechnologyChanged=" + hasDataRadioTechnologyChanged 313 + " hasChanged=" + hasChanged 314 + " hasRoamingOn=" + hasRoamingOn 315 + " hasRoamingOff=" + hasRoamingOff 316 + " hasLocationChanged=" + hasLocationChanged 317 + " has4gHandoff = " + has4gHandoff 318 + " hasMultiApnSupport=" + hasMultiApnSupport 319 + " hasLostMultiApnSupport=" + hasLostMultiApnSupport); 320 } 321 // Add an event log when connection state changes 322 if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState() 323 || mSS.getDataRegState() != mNewSS.getDataRegState()) { 324 EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, mSS.getVoiceRegState(), 325 mSS.getDataRegState(), mNewSS.getVoiceRegState(), mNewSS.getDataRegState()); 326 } 327 328 ServiceState tss; 329 tss = mSS; 330 mSS = mNewSS; 331 mNewSS = tss; 332 // clean slate for next time 333 mNewSS.setStateOutOfService(); 334 335 CdmaCellLocation tcl = mCellLoc; 336 mCellLoc = mNewCellLoc; 337 mNewCellLoc = tcl; 338 339 mNewSS.setStateOutOfService(); // clean slate for next time 340 341 if (hasDataRadioTechnologyChanged) { 342 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 343 ServiceState.rilRadioTechnologyToString(mSS.getRilDataRadioTechnology())); 344 } 345 346 if (hasRegistered) { 347 mNetworkAttachedRegistrants.notifyRegistrants(); 348 } 349 350 if (hasChanged) { 351 if (mPhone.isEriFileLoaded()) { 352 String eriText; 353 // Now the CDMAPhone sees the new ServiceState so it can get the 354 // new ERI text 355 if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { 356 eriText = mPhone.getCdmaEriText(); 357 } else if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF) { 358 eriText = (mIccRecords != null) ? mIccRecords.getServiceProviderName() : null; 359 if (TextUtils.isEmpty(eriText)) { 360 // Sets operator alpha property by retrieving from 361 // build-time system property 362 eriText = SystemProperties.get("ro.cdma.home.operator.alpha"); 363 } 364 } else { 365 // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used 366 // for mRegistrationState 0,2,3 and 4 367 eriText = mPhone.getContext() 368 .getText(com.android.internal.R.string.roamingTextSearching).toString(); 369 } 370 mSS.setOperatorAlphaLong(eriText); 371 } 372 373 if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY && 374 mIccRecords != null) { 375 // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches 376 // one configured in SIM, use operator name from CSIM record. 377 boolean showSpn = 378 ((RuimRecords)mIccRecords).getCsimSpnDisplayCondition(); 379 int iconIndex = mSS.getCdmaEriIconIndex(); 380 381 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) && 382 isInHomeSidNid(mSS.getSystemId(), mSS.getNetworkId()) && 383 mIccRecords != null) { 384 mSS.setOperatorAlphaLong(mIccRecords.getServiceProviderName()); 385 } 386 } 387 388 String operatorNumeric; 389 390 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 391 mSS.getOperatorAlphaLong()); 392 393 String prevOperatorNumeric = 394 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); 395 operatorNumeric = mSS.getOperatorNumeric(); 396 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 397 398 if (operatorNumeric == null) { 399 if (DBG) log("operatorNumeric is null"); 400 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 401 mGotCountryCode = false; 402 } else { 403 String isoCountryCode = ""; 404 String mcc = operatorNumeric.substring(0, 3); 405 try { 406 isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric 407 .substring(0, 3))); 408 } catch (NumberFormatException ex) { 409 loge("countryCodeForMcc error" + ex); 410 } catch (StringIndexOutOfBoundsException ex) { 411 loge("countryCodeForMcc error" + ex); 412 } 413 414 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, 415 isoCountryCode); 416 mGotCountryCode = true; 417 418 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric, 419 mNeedFixZone)) { 420 fixTimeZone(isoCountryCode); 421 } 422 } 423 424 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 425 mSS.getRoaming() ? "true" : "false"); 426 427 updateSpnDisplay(); 428 mPhone.notifyServiceStateChanged(mSS); 429 } 430 431 if (hasCdmaDataConnectionAttached || has4gHandoff) { 432 mAttachedRegistrants.notifyRegistrants(); 433 } 434 435 if (hasCdmaDataConnectionDetached) { 436 mDetachedRegistrants.notifyRegistrants(); 437 } 438 439 if ((hasCdmaDataConnectionChanged || hasDataRadioTechnologyChanged)) { 440 log("pollStateDone: call notifyDataConnection"); 441 mPhone.notifyDataConnection(null); 442 } 443 444 if (hasRoamingOn) { 445 mRoamingOnRegistrants.notifyRegistrants(); 446 } 447 448 if (hasRoamingOff) { 449 mRoamingOffRegistrants.notifyRegistrants(); 450 } 451 452 if (hasLocationChanged) { 453 mPhone.notifyLocationChanged(); 454 } 455 456 ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>(); 457 synchronized(mCellInfo) { 458 CellInfoLte cil = (CellInfoLte)mCellInfo; 459 460 boolean cidChanged = ! mNewCellIdentityLte.equals(mLasteCellIdentityLte); 461 if (hasRegistered || hasDeregistered || cidChanged) { 462 // TODO: Handle the absence of LteCellIdentity 463 long timeStamp = SystemClock.elapsedRealtime() * 1000; 464 boolean registered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 465 mLasteCellIdentityLte = mNewCellIdentityLte; 466 467 cil.setRegisterd(registered); 468 cil.setCellIdentity(mLasteCellIdentityLte); 469 if (DBG) { 470 log("pollStateDone: hasRegistered=" + hasRegistered + 471 " hasDeregistered=" + hasDeregistered + 472 " cidChanged=" + cidChanged + 473 " mCellInfo=" + mCellInfo); 474 } 475 arrayCi.add(mCellInfo); 476 } 477 mPhoneBase.notifyCellInfo(arrayCi); 478 } 479 } 480 481 @Override 482 protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) { 483 if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 484 isGsm = true; 485 } 486 boolean ssChanged = super.onSignalStrengthResult(ar, isGsm); 487 488 synchronized (mCellInfo) { 489 if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 490 mCellInfoLte.setTimeStamp(SystemClock.elapsedRealtime() * 1000); 491 mCellInfoLte.setTimeStampType(CellInfo.TIMESTAMP_TYPE_JAVA_RIL); 492 mCellInfoLte.getCellSignalStrength() 493 .initialize(mSignalStrength,SignalStrength.INVALID); 494 } 495 if (mCellInfoLte.getCellIdentity() != null) { 496 ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>(); 497 arrayCi.add(mCellInfoLte); 498 mPhoneBase.notifyCellInfo(arrayCi); 499 } 500 } 501 return ssChanged; 502 } 503 504 @Override 505 public boolean isConcurrentVoiceAndDataAllowed() { 506 // For non-LTE, look at the CSS indicator to check on Concurrent V & D capability 507 if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 508 return true; 509 } else { 510 return mSS.getCssIndicator() == 1; 511 } 512 } 513 514 /** 515 * Check whether the specified SID and NID pair appears in the HOME SID/NID list 516 * read from NV or SIM. 517 * 518 * @return true if provided sid/nid pair belongs to operator's home network. 519 */ 520 private boolean isInHomeSidNid(int sid, int nid) { 521 // if SID/NID is not available, assume this is home network. 522 if (isSidsAllZeros()) return true; 523 524 // length of SID/NID shold be same 525 if (mHomeSystemId.length != mHomeNetworkId.length) return true; 526 527 if (sid == 0) return true; 528 529 for (int i = 0; i < mHomeSystemId.length; i++) { 530 // Use SID only if NID is a reserved value. 531 // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2) 532 if ((mHomeSystemId[i] == sid) && 533 ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) || 534 (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) { 535 return true; 536 } 537 } 538 // SID/NID are not in the list. So device is not in home network 539 return false; 540 } 541 542 /** 543 * TODO: Remove when we get new ril/modem for Galaxy Nexus. 544 * 545 * @return all available cell information, the returned List maybe empty but never null. 546 */ 547 @Override 548 public List<CellInfo> getAllCellInfo() { 549 if (mCi.getRilVersion() >= 8) { 550 return super.getAllCellInfo(); 551 } else { 552 ArrayList<CellInfo> arrayList = new ArrayList<CellInfo>(); 553 CellInfo ci; 554 synchronized(mCellInfo) { 555 arrayList.add(mCellInfoLte); 556 } 557 if (DBG) log ("getAllCellInfo: arrayList=" + arrayList); 558 return arrayList; 559 } 560 } 561 562 @Override 563 protected void log(String s) { 564 Rlog.d(LOG_TAG, "[CdmaLteSST] " + s); 565 } 566 567 @Override 568 protected void loge(String s) { 569 Rlog.e(LOG_TAG, "[CdmaLteSST] " + s); 570 } 571 572 @Override 573 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 574 pw.println("CdmaLteServiceStateTracker extends:"); 575 super.dump(fd, pw, args); 576 pw.println(" mCdmaLtePhone=" + mCdmaLtePhone); 577 } 578 } 579