CdmaLteServiceStateTracker.java revision d6bcfd1cd081b9fe553976a0191a814b929c583e
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.telephony.SignalStrength; 25import android.telephony.ServiceState; 26import android.telephony.cdma.CdmaCellLocation; 27import android.os.AsyncResult; 28import android.os.Message; 29 30 31import android.util.Log; 32import android.util.EventLog; 33 34import com.android.internal.telephony.gsm.GsmDataConnectionTracker; 35 36public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { 37 CDMALTEPhone mCdmaLtePhone; 38 39 private ServiceState mLteSS; // The last LTE state from Voice Registration 40 41 public CdmaLteServiceStateTracker(CDMALTEPhone phone) { 42 super(phone); 43 cm.registerForSIMReady(this, EVENT_SIM_READY, null); 44 mCdmaLtePhone = phone; 45 46 mLteSS = new ServiceState(); 47 if (DBG) log("CdmaLteServiceStateTracker Constructors"); 48 } 49 50 @Override 51 public void dispose() { 52 cm.unregisterForSIMReady(this); 53 super.dispose(); 54 } 55 56 @Override 57 public void handleMessage(Message msg) { 58 AsyncResult ar; 59 int[] ints; 60 String[] strings; 61 switch (msg.what) { 62 case EVENT_POLL_STATE_GPRS: 63 if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS"); 64 ar = (AsyncResult)msg.obj; 65 handlePollStateResult(msg.what, ar); 66 break; 67 case EVENT_SIM_READY: 68 if (DBG) log("handleMessage EVENT_SIM_READY"); 69 isSubscriptionFromRuim = false; 70 cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); 71 pollState(); 72 // Signal strength polling stops when radio is off. 73 queueNextSignalStrengthPoll(); 74 break; 75 default: 76 super.handleMessage(msg); 77 } 78 } 79 80 /** 81 * Set the cdmaSS for EVENT_POLL_STATE_REGISTRATION_CDMA 82 */ 83 @Override 84 protected void setCdmaTechnology(int radioTechnology) { 85 // Called on voice registration state response. 86 // Just record new CDMA radio technology 87 newSS.setRadioTechnology(radioTechnology); 88 } 89 90 /** 91 * Handle the result of one of the pollState()-related requests 92 */ 93 @Override 94 protected void handlePollStateResultMessage(int what, AsyncResult ar) { 95 if (what == EVENT_POLL_STATE_GPRS) { 96 if (DBG) log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS"); 97 String states[] = (String[])ar.result; 98 99 int type = 0; 100 int regState = -1; 101 if (states.length > 0) { 102 try { 103 regState = Integer.parseInt(states[0]); 104 105 // states[3] (if present) is the current radio technology 106 if (states.length >= 4 && states[3] != null) { 107 type = Integer.parseInt(states[3]); 108 } 109 } catch (NumberFormatException ex) { 110 loge("handlePollStateResultMessage: error parsing GprsRegistrationState: " 111 + ex); 112 } 113 } 114 115 // Not sure if this is needed in CDMALTE phone. 116 // mDataRoaming = regCodeIsRoaming(regState); 117 mLteSS.setRadioTechnology(type); 118 mLteSS.setState(regCodeToServiceState(regState)); 119 } else { 120 super.handlePollStateResultMessage(what, ar); 121 } 122 } 123 124 @Override 125 protected void setSignalStrengthDefaultValues() { 126 mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, false); 127 } 128 129 @Override 130 protected void pollState() { 131 pollingContext = new int[1]; 132 pollingContext[0] = 0; 133 134 switch (cm.getRadioState()) { 135 case RADIO_UNAVAILABLE: 136 newSS.setStateOutOfService(); 137 newCellLoc.setStateInvalid(); 138 setSignalStrengthDefaultValues(); 139 mGotCountryCode = false; 140 141 pollStateDone(); 142 break; 143 144 case RADIO_OFF: 145 newSS.setStateOff(); 146 newCellLoc.setStateInvalid(); 147 setSignalStrengthDefaultValues(); 148 mGotCountryCode = false; 149 150 pollStateDone(); 151 break; 152 153 default: 154 // Issue all poll-related commands at once, then count 155 // down the responses which are allowed to arrive 156 // out-of-order. 157 158 pollingContext[0]++; 159 // RIL_REQUEST_OPERATOR is necessary for CDMA 160 cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); 161 162 pollingContext[0]++; 163 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA 164 cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, 165 pollingContext)); 166 167 int networkMode = android.provider.Settings.Secure.getInt(phone.getContext() 168 .getContentResolver(), 169 android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, 170 RILConstants.PREFERRED_NETWORK_MODE); 171 if (DBG) log("pollState: network mode here is = " + networkMode); 172 if ((networkMode == RILConstants.NETWORK_MODE_GLOBAL) 173 || (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY)) { 174 pollingContext[0]++; 175 // RIL_REQUEST_DATA_REGISTRATION_STATE 176 cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, 177 pollingContext)); 178 } 179 break; 180 } 181 } 182 183 @Override 184 protected void pollStateDone() { 185 // determine data NetworkType from both LET and CDMA SS 186 if (mLteSS.getState() == ServiceState.STATE_IN_SERVICE) { 187 //in LTE service 188 newNetworkType = mLteSS.getRadioTechnology(); 189 mNewDataConnectionState = mLteSS.getState(); 190 newSS.setRadioTechnology(newNetworkType); 191 log("pollStateDone LTE/eHRPD STATE_IN_SERVICE newNetworkType = " + newNetworkType); 192 } else { 193 // LTE out of service, get CDMA Service State 194 newNetworkType = newSS.getRadioTechnology(); 195 mNewDataConnectionState = radioTechnologyToDataServiceState(newNetworkType); 196 log("pollStateDone CDMA STATE_IN_SERVICE newNetworkType = " + newNetworkType + 197 " mNewDataConnectionState = " + mNewDataConnectionState); 198 } 199 200 if (DBG) log("pollStateDone: oldSS=[" + ss + "] newSS=[" + newSS + "]"); 201 202 boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE 203 && newSS.getState() == ServiceState.STATE_IN_SERVICE; 204 205 boolean hasDeregistered = ss.getState() == ServiceState.STATE_IN_SERVICE 206 && newSS.getState() != ServiceState.STATE_IN_SERVICE; 207 208 boolean hasCdmaDataConnectionAttached = 209 mDataConnectionState != ServiceState.STATE_IN_SERVICE 210 && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE; 211 212 boolean hasCdmaDataConnectionDetached = 213 mDataConnectionState == ServiceState.STATE_IN_SERVICE 214 && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE; 215 216 boolean hasCdmaDataConnectionChanged = 217 mDataConnectionState != mNewDataConnectionState; 218 219 boolean hasNetworkTypeChanged = networkType != newNetworkType; 220 221 boolean hasChanged = !newSS.equals(ss); 222 223 boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming(); 224 225 boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming(); 226 227 boolean hasLocationChanged = !newCellLoc.equals(cellLoc); 228 229 boolean has4gHandoff = 230 ((networkType == ServiceState.RADIO_TECHNOLOGY_LTE) && 231 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) || 232 ((networkType == ServiceState.RADIO_TECHNOLOGY_EHRPD) && 233 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE)); 234 235 boolean hasMultiApnSupport = 236 (((newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE) || 237 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) && 238 ((networkType != ServiceState.RADIO_TECHNOLOGY_LTE) && 239 (networkType != ServiceState.RADIO_TECHNOLOGY_EHRPD))); 240 241 boolean hasLostMultiApnSupport = 242 ((newNetworkType >= ServiceState.RADIO_TECHNOLOGY_IS95A) && 243 (newNetworkType <= ServiceState.RADIO_TECHNOLOGY_EVDO_A)); 244 245 if (DBG) { 246 log("pollStateDone:" 247 + " hasRegistered=" + hasRegistered 248 + " hasDeegistered=" + hasDeregistered 249 + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached 250 + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached 251 + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged 252 + " hasNetworkTypeChanged = " + hasNetworkTypeChanged 253 + " hasChanged=" + hasChanged 254 + " hasRoamingOn=" + hasRoamingOn 255 + " hasRoamingOff=" + hasRoamingOff 256 + " hasLocationChanged=" + hasLocationChanged 257 + " has4gHandoff = " + has4gHandoff 258 + " hasMultiApnSupport=" + hasMultiApnSupport 259 + " hasLostMultiApnSupport=" + hasLostMultiApnSupport); 260 } 261 // Add an event log when connection state changes 262 if (ss.getState() != newSS.getState() 263 || mDataConnectionState != mNewDataConnectionState) { 264 EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(), 265 mDataConnectionState, newSS.getState(), mNewDataConnectionState); 266 } 267 268 ServiceState tss; 269 tss = ss; 270 ss = newSS; 271 newSS = tss; 272 // clean slate for next time 273 newSS.setStateOutOfService(); 274 mLteSS.setStateOutOfService(); 275 276 if ((hasMultiApnSupport) 277 && (phone.mDataConnectionTracker instanceof CdmaDataConnectionTracker)) { 278 if (DBG) log("GsmDataConnectionTracker Created"); 279 phone.mDataConnectionTracker.dispose(); 280 phone.mDataConnectionTracker = new GsmDataConnectionTracker(mCdmaLtePhone); 281 } 282 283 if ((hasLostMultiApnSupport) 284 && (phone.mDataConnectionTracker instanceof GsmDataConnectionTracker)) { 285 if (DBG)log("GsmDataConnectionTracker disposed"); 286 phone.mDataConnectionTracker.dispose(); 287 phone.mDataConnectionTracker = new CdmaDataConnectionTracker(phone); 288 } 289 290 CdmaCellLocation tcl = cellLoc; 291 cellLoc = newCellLoc; 292 newCellLoc = tcl; 293 294 mDataConnectionState = mNewDataConnectionState; 295 networkType = newNetworkType; 296 297 newSS.setStateOutOfService(); // clean slate for next time 298 299 if (hasNetworkTypeChanged) { 300 phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 301 ServiceState.radioTechnologyToString(networkType)); 302 } 303 304 if (hasRegistered) { 305 mNetworkAttachedRegistrants.notifyRegistrants(); 306 } 307 308 if (hasChanged) { 309 if (cm.getNvState().isNVReady()) { 310 String eriText; 311 // Now the CDMAPhone sees the new ServiceState so it can get the 312 // new ERI text 313 if (ss.getState() == ServiceState.STATE_IN_SERVICE) { 314 eriText = phone.getCdmaEriText(); 315 } else { 316 // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used 317 // for 318 // mRegistrationState 0,2,3 and 4 319 eriText = phone.getContext() 320 .getText(com.android.internal.R.string.roamingTextSearching).toString(); 321 } 322 ss.setOperatorAlphaLong(eriText); 323 } 324 if (cm.getSimState().isSIMReady()) { 325 // SIM is found on the device. Read the operator name from the card. 326 ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName()); 327 328 // If SIM card is present, Eri will not be used. Turn it off 329 ss.setCdmaEriIconIndex(EriInfo.ROAMING_INDICATOR_OFF); 330 } 331 332 String operatorNumeric; 333 334 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 335 ss.getOperatorAlphaLong()); 336 337 operatorNumeric = ss.getOperatorNumeric(); 338 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 339 340 if (operatorNumeric == null) { 341 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 342 } else { 343 String isoCountryCode = ""; 344 try { 345 isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric 346 .substring(0, 3))); 347 } catch (NumberFormatException ex) { 348 loge("countryCodeForMcc error" + ex); 349 } catch (StringIndexOutOfBoundsException ex) { 350 loge("countryCodeForMcc error" + ex); 351 } 352 353 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, 354 isoCountryCode); 355 mGotCountryCode = true; 356 if (mNeedFixZone) { 357 fixTimeZone(isoCountryCode); 358 } 359 } 360 361 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 362 ss.getRoaming() ? "true" : "false"); 363 364 updateSpnDisplay(); 365 phone.notifyServiceStateChanged(ss); 366 } 367 368 if (hasCdmaDataConnectionAttached) { 369 mAttachedRegistrants.notifyRegistrants(); 370 } 371 372 if (hasCdmaDataConnectionDetached) { 373 mDetachedRegistrants.notifyRegistrants(); 374 } 375 376 if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)) { 377 phone.notifyDataConnection(); 378 } 379 380 if (hasRoamingOn) { 381 mRoamingOnRegistrants.notifyRegistrants(); 382 } 383 384 if (hasRoamingOff) { 385 mRoamingOffRegistrants.notifyRegistrants(); 386 } 387 388 if (hasLocationChanged) { 389 phone.notifyLocationChanged(); 390 } 391 } 392 393 @Override 394 protected void onSignalStrengthResult(AsyncResult ar) { 395 SignalStrength oldSignalStrength = mSignalStrength; 396 397 if (ar.exception != null) { 398 // Most likely radio is resetting/disconnected change to default 399 // values. 400 setSignalStrengthDefaultValues(); 401 } else { 402 int[] ints = (int[])ar.result; 403 int lteCqi = 99, lteRsrp = -1; 404 int lteRssi = 99; 405 int offset = 2; 406 int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120; 407 int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160; 408 int evdoRssi = (ints[offset + 2] > 0) ? -ints[offset + 2] : -120; 409 int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1; 410 int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4] 411 : -1; 412 if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) { 413 lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99; 414 lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1; 415 lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99; 416 } 417 418 if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) { 419 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio, 420 evdoSnr, false); 421 } else { 422 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio, 423 evdoSnr, lteRssi, lteRsrp, -1, -1, lteCqi, true); 424 } 425 } 426 427 try { 428 phone.notifySignalStrength(); 429 } catch (NullPointerException ex) { 430 loge("onSignalStrengthResult() Phone already destroyed: " + ex 431 + "SignalStrength not notified"); 432 } 433 } 434 435 @Override 436 public boolean isConcurrentVoiceAndDataAllowed() { 437 // Note: it needs to be confirmed which CDMA network types 438 // can support voice and data calls concurrently. 439 // For the time-being, the return value will be false. 440 // return (networkType >= ServiceState.RADIO_TECHNOLOGY_LTE); 441 return false; 442 } 443 444 /** 445 * Returns OTASP_NOT_NEEDED as its not needed for LTE 446 */ 447 @Override 448 int getOtasp() { 449 int provisioningState = OTASP_NOT_NEEDED; 450 if (DBG) log("getOtasp: state=" + provisioningState); 451 return provisioningState; 452 } 453 454 @Override 455 protected void log(String s) { 456 Log.d(LOG_TAG, "[CdmaLteSST] " + s); 457 } 458 459 @Override 460 protected void loge(String s) { 461 Log.e(LOG_TAG, "[CdmaLteSST] " + s); 462 } 463} 464