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