2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.internal.telephony.cdma;
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.RILConstants;
24 import android.content.Intent;
25 import android.telephony.SignalStrength;
26 import android.telephony.ServiceState;
27 import android.telephony.cdma.CdmaCellLocation;
28 import android.os.AsyncResult;
29 import android.os.Message;
30 import android.provider.Telephony.Intents;
32 import android.text.TextUtils;
33 import android.util.Log;
34 import android.util.EventLog;
36 import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
38 public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
39 CDMALTEPhone mCdmaLtePhone;
41 private ServiceState mLteSS; // The last LTE state from Voice Registration
42 private String mCurrentSpn = null;
44 public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
46 cm.registerForSIMReady(this, EVENT_SIM_READY, null);
47 mCdmaLtePhone = phone;
49 mLteSS = new ServiceState();
50 if (DBG) log("CdmaLteServiceStateTracker Constructors");
54 public void dispose() {
55 cm.unregisterForSIMReady(this);
60 public void handleMessage(Message msg) {
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);
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 phone.mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
77 // Signal strength polling stops when radio is off.
78 queueNextSignalStrengthPoll();
83 case EVENT_SIM_RECORDS_LOADED:
84 CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords;
85 if ((sim != null) && sim.isProvisioned()) {
88 parseSidNid(sim.getSid(), sim.getNid());
89 mPrlVersion = sim.getPrlVersion();;
90 mIsMinInfoReady = true;
93 // SID/NID/PRL is loaded. Poll service state
94 // again to update to the roaming state with
95 // the latest variables.
99 super.handleMessage(msg);
104 * Set the cdmaSS for EVENT_POLL_STATE_REGISTRATION_CDMA
107 protected void setCdmaTechnology(int radioTechnology) {
108 // Called on voice registration state response.
109 // Just record new CDMA radio technology
110 newSS.setRadioTechnology(radioTechnology);
114 * Handle the result of one of the pollState()-related requests
117 protected void handlePollStateResultMessage(int what, AsyncResult ar) {
118 if (what == EVENT_POLL_STATE_GPRS) {
119 if (DBG) log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS");
120 String states[] = (String[])ar.result;
124 if (states.length > 0) {
126 regState = Integer.parseInt(states[0]);
128 // states[3] (if present) is the current radio technology
129 if (states.length >= 4 && states[3] != null) {
130 type = Integer.parseInt(states[3]);
132 } catch (NumberFormatException ex) {
133 loge("handlePollStateResultMessage: error parsing GprsRegistrationState: "
138 // Not sure if this is needed in CDMALTE phone.
139 // mDataRoaming = regCodeIsRoaming(regState);
140 mLteSS.setRadioTechnology(type);
141 mLteSS.setState(regCodeToServiceState(regState));
143 super.handlePollStateResultMessage(what, ar);
148 protected void setSignalStrengthDefaultValues() {
149 mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, false);
153 protected void pollState() {
154 pollingContext = new int[1];
155 pollingContext[0] = 0;
157 switch (cm.getRadioState()) {
158 case RADIO_UNAVAILABLE:
159 newSS.setStateOutOfService();
160 newCellLoc.setStateInvalid();
161 setSignalStrengthDefaultValues();
162 mGotCountryCode = false;
169 newCellLoc.setStateInvalid();
170 setSignalStrengthDefaultValues();
171 mGotCountryCode = false;
177 // Issue all poll-related commands at once, then count
178 // down the responses which are allowed to arrive
182 // RIL_REQUEST_OPERATOR is necessary for CDMA
183 cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext));
186 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA
187 cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA,
190 int networkMode = android.provider.Settings.Secure.getInt(phone.getContext()
191 .getContentResolver(),
192 android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
193 RILConstants.PREFERRED_NETWORK_MODE);
194 if (DBG) log("pollState: network mode here is = " + networkMode);
195 if ((networkMode == RILConstants.NETWORK_MODE_GLOBAL)
196 || (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY)) {
198 // RIL_REQUEST_DATA_REGISTRATION_STATE
199 cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS,
207 protected void pollStateDone() {
208 // determine data NetworkType from both LET and CDMA SS
209 if (mLteSS.getState() == ServiceState.STATE_IN_SERVICE) {
211 newNetworkType = mLteSS.getRadioTechnology();
212 mNewDataConnectionState = mLteSS.getState();
213 newSS.setRadioTechnology(newNetworkType);
214 log("pollStateDone LTE/eHRPD STATE_IN_SERVICE newNetworkType = " + newNetworkType);
216 // LTE out of service, get CDMA Service State
217 newNetworkType = newSS.getRadioTechnology();
218 mNewDataConnectionState = radioTechnologyToDataServiceState(newNetworkType);
219 log("pollStateDone CDMA STATE_IN_SERVICE newNetworkType = " + newNetworkType +
220 " mNewDataConnectionState = " + mNewDataConnectionState);
223 if (DBG) log("pollStateDone: oldSS=[" + ss + "] newSS=[" + newSS + "]");
225 boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE
226 && newSS.getState() == ServiceState.STATE_IN_SERVICE;
228 boolean hasDeregistered = ss.getState() == ServiceState.STATE_IN_SERVICE
229 && newSS.getState() != ServiceState.STATE_IN_SERVICE;
231 boolean hasCdmaDataConnectionAttached =
232 mDataConnectionState != ServiceState.STATE_IN_SERVICE
233 && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE;
235 boolean hasCdmaDataConnectionDetached =
236 mDataConnectionState == ServiceState.STATE_IN_SERVICE
237 && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE;
239 boolean hasCdmaDataConnectionChanged =
240 mDataConnectionState != mNewDataConnectionState;
242 boolean hasNetworkTypeChanged = networkType != newNetworkType;
244 boolean hasChanged = !newSS.equals(ss);
246 boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming();
248 boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming();
250 boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
252 boolean has4gHandoff =
253 ((networkType == ServiceState.RADIO_TECHNOLOGY_LTE) &&
254 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) ||
255 ((networkType == ServiceState.RADIO_TECHNOLOGY_EHRPD) &&
256 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE));
258 boolean hasMultiApnSupport =
259 (((newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE) ||
260 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) &&
261 ((networkType != ServiceState.RADIO_TECHNOLOGY_LTE) &&
262 (networkType != ServiceState.RADIO_TECHNOLOGY_EHRPD)));
264 boolean hasLostMultiApnSupport =
265 ((newNetworkType >= ServiceState.RADIO_TECHNOLOGY_IS95A) &&
266 (newNetworkType <= ServiceState.RADIO_TECHNOLOGY_EVDO_A));
270 + " hasRegistered=" + hasRegistered
271 + " hasDeegistered=" + hasDeregistered
272 + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached
273 + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached
274 + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged
275 + " hasNetworkTypeChanged = " + hasNetworkTypeChanged
276 + " hasChanged=" + hasChanged
277 + " hasRoamingOn=" + hasRoamingOn
278 + " hasRoamingOff=" + hasRoamingOff
279 + " hasLocationChanged=" + hasLocationChanged
280 + " has4gHandoff = " + has4gHandoff
281 + " hasMultiApnSupport=" + hasMultiApnSupport
282 + " hasLostMultiApnSupport=" + hasLostMultiApnSupport);
284 // Add an event log when connection state changes
285 if (ss.getState() != newSS.getState()
286 || mDataConnectionState != mNewDataConnectionState) {
287 EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(),
288 mDataConnectionState, newSS.getState(), mNewDataConnectionState);
295 // clean slate for next time
296 newSS.setStateOutOfService();
297 mLteSS.setStateOutOfService();
299 if ((hasMultiApnSupport)
300 && (phone.mDataConnectionTracker instanceof CdmaDataConnectionTracker)) {
301 if (DBG) log("GsmDataConnectionTracker Created");
302 phone.mDataConnectionTracker.dispose();
303 phone.mDataConnectionTracker = new GsmDataConnectionTracker(mCdmaLtePhone);
306 if ((hasLostMultiApnSupport)
307 && (phone.mDataConnectionTracker instanceof GsmDataConnectionTracker)) {
308 if (DBG)log("GsmDataConnectionTracker disposed");
309 phone.mDataConnectionTracker.dispose();
310 phone.mDataConnectionTracker = new CdmaDataConnectionTracker(phone);
313 CdmaCellLocation tcl = cellLoc;
314 cellLoc = newCellLoc;
317 mDataConnectionState = mNewDataConnectionState;
318 networkType = newNetworkType;
320 newSS.setStateOutOfService(); // clean slate for next time
322 if (hasNetworkTypeChanged) {
323 phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
324 ServiceState.radioTechnologyToString(networkType));
328 mNetworkAttachedRegistrants.notifyRegistrants();
332 if (phone.isEriFileLoaded()) {
334 // Now the CDMAPhone sees the new ServiceState so it can get the
336 if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
337 eriText = phone.getCdmaEriText();
339 // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used
341 // mRegistrationState 0,2,3 and 4
342 eriText = phone.getContext()
343 .getText(com.android.internal.R.string.roamingTextSearching).toString();
345 ss.setOperatorAlphaLong(eriText);
348 String operatorNumeric;
350 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
351 ss.getOperatorAlphaLong());
353 operatorNumeric = ss.getOperatorNumeric();
354 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
356 if (operatorNumeric == null) {
357 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
359 String isoCountryCode = "";
361 isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric
363 } catch (NumberFormatException ex) {
364 loge("countryCodeForMcc error" + ex);
365 } catch (StringIndexOutOfBoundsException ex) {
366 loge("countryCodeForMcc error" + ex);
369 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
371 mGotCountryCode = true;
373 fixTimeZone(isoCountryCode);
377 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
378 ss.getRoaming() ? "true" : "false");
381 phone.notifyServiceStateChanged(ss);
384 if (hasCdmaDataConnectionAttached) {
385 mAttachedRegistrants.notifyRegistrants();
388 if (hasCdmaDataConnectionDetached) {
389 mDetachedRegistrants.notifyRegistrants();
392 if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)) {
393 phone.notifyDataConnection();
397 mRoamingOnRegistrants.notifyRegistrants();
401 mRoamingOffRegistrants.notifyRegistrants();
404 if (hasLocationChanged) {
405 phone.notifyLocationChanged();
410 protected void onSignalStrengthResult(AsyncResult ar) {
411 SignalStrength oldSignalStrength = mSignalStrength;
413 if (ar.exception != null) {
414 // Most likely radio is resetting/disconnected change to default
416 setSignalStrengthDefaultValues();
418 int[] ints = (int[])ar.result;
419 int lteCqi = 99, lteRsrp = -1;
422 int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
423 int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160;
424 int evdoRssi = (ints[offset + 2] > 0) ? -ints[offset + 2] : -120;
425 int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1;
426 int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4]
428 if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
429 lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
430 lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1;
431 lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99;
434 if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
435 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
438 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
439 evdoSnr, lteRssi, lteRsrp, -1, -1, lteCqi, true);
444 phone.notifySignalStrength();
445 } catch (NullPointerException ex) {
446 loge("onSignalStrengthResult() Phone already destroyed: " + ex
447 + "SignalStrength not notified");
452 public boolean isConcurrentVoiceAndDataAllowed() {
453 // Note: it needs to be confirmed which CDMA network types
454 // can support voice and data calls concurrently.
455 // For the time-being, the return value will be false.
456 // return (networkType >= ServiceState.RADIO_TECHNOLOGY_LTE);
461 * Returns OTASP_NOT_NEEDED as its not needed for LTE
465 int provisioningState = OTASP_NOT_NEEDED;
466 if (DBG) log("getOtasp: state=" + provisioningState);
467 return provisioningState;
471 protected void updateSpnDisplay() {
472 // mOperatorAlphaLong contains the ERI text
473 String plmn = ss.getOperatorAlphaLong();
475 boolean showSpn = false;
477 if (cm.getSimState().isSIMReady()) {
478 // SIM is found on the device. Read the operator name from the card.
479 showSpn = ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
480 spn = phone.mIccRecords.getServiceProviderName();
482 // double check we are not printing identicall test
483 if (TextUtils.equals(plmn, spn)) showSpn = false;
486 if (!TextUtils.equals(plmn, mCurPlmn) ||
487 !TextUtils.equals(spn, mCurrentSpn)) {
488 boolean showPlmn = plmn != null;
490 log(String.format("updateSpnDisplay: changed sending intent" +
491 " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s'",
492 showPlmn, plmn, showSpn, spn));
494 Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION);
495 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
496 intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn);
497 intent.putExtra(Intents.EXTRA_SPN, spn);
498 intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn);
499 intent.putExtra(Intents.EXTRA_PLMN, plmn);
500 phone.getContext().sendStickyBroadcast(intent);
508 protected void log(String s) {
509 Log.d(LOG_TAG, "[CdmaLteSST] " + s);
513 protected void loge(String s) {
514 Log.e(LOG_TAG, "[CdmaLteSST] " + s);