| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.internal.telephony.cdma; |
| |
| import android.content.Context; |
| import android.content.Intent; |
| import com.android.internal.telephony.TelephonyProperties; |
| import com.android.internal.telephony.MccTable; |
| import com.android.internal.telephony.EventLogTags; |
| import com.android.internal.telephony.uicc.RuimRecords; |
| import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; |
| import com.android.internal.telephony.TelephonyIntents; |
| import com.android.internal.telephony.Phone; |
| import com.android.internal.telephony.PhoneConstants; |
| import com.android.internal.telephony.PhoneFactory; |
| import com.android.internal.telephony.dataconnection.DcTrackerBase; |
| import com.android.internal.telephony.PhoneConstants; |
| |
| import android.telephony.CellInfo; |
| import android.telephony.CellInfoLte; |
| import android.telephony.CellSignalStrengthLte; |
| import android.telephony.CellIdentityLte; |
| import android.telephony.SignalStrength; |
| import android.telephony.ServiceState; |
| import android.telephony.cdma.CdmaCellLocation; |
| import android.telephony.TelephonyManager; |
| import android.text.TextUtils; |
| import android.os.AsyncResult; |
| import android.os.Build; |
| import android.os.Message; |
| import android.os.UserHandle; |
| import android.os.SystemClock; |
| import android.os.SystemProperties; |
| |
| import android.telephony.Rlog; |
| import android.util.EventLog; |
| |
| import com.android.internal.telephony.dataconnection.DcTrackerBase; |
| import com.android.internal.telephony.ProxyController; |
| import android.telephony.SubscriptionManager; |
| import com.android.internal.telephony.uicc.UiccCardApplication; |
| import com.android.internal.telephony.uicc.UiccController; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { |
| private CDMALTEPhone mCdmaLtePhone; |
| private final CellInfoLte mCellInfoLte; |
| private static final int EVENT_ALL_DATA_DISCONNECTED = 1001; |
| |
| private CellIdentityLte mNewCellIdentityLte = new CellIdentityLte(); |
| private CellIdentityLte mLasteCellIdentityLte = new CellIdentityLte(); |
| |
| public CdmaLteServiceStateTracker(CDMALTEPhone phone) { |
| super(phone, new CellInfoLte()); |
| mCdmaLtePhone = phone; |
| mCdmaLtePhone.registerForSimRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); |
| mCellInfoLte = (CellInfoLte) mCellInfo; |
| |
| ((CellInfoLte)mCellInfo).setCellSignalStrength(new CellSignalStrengthLte()); |
| ((CellInfoLte)mCellInfo).setCellIdentity(new CellIdentityLte()); |
| |
| if (DBG) log("CdmaLteServiceStateTracker Constructors"); |
| } |
| |
| @Override |
| public void dispose() { |
| mPhone.unregisterForSimRecordsLoaded(this); |
| super.dispose(); |
| } |
| |
| @Override |
| public void handleMessage(Message msg) { |
| AsyncResult ar; |
| int[] ints; |
| String[] strings; |
| |
| if (!mPhone.mIsTheCurrentActivePhone) { |
| loge("Received message " + msg + "[" + msg.what + "]" + |
| " while being destroyed. Ignoring."); |
| return; |
| } |
| |
| if (DBG) log("handleMessage: " + msg.what); |
| switch (msg.what) { |
| case EVENT_POLL_STATE_GPRS: |
| if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS"); |
| ar = (AsyncResult)msg.obj; |
| handlePollStateResult(msg.what, ar); |
| break; |
| case EVENT_RUIM_RECORDS_LOADED: |
| updatePhoneObject(); |
| RuimRecords ruim = (RuimRecords)mIccRecords; |
| if (ruim != null) { |
| if (ruim.isProvisioned()) { |
| mMdn = ruim.getMdn(); |
| mMin = ruim.getMin(); |
| parseSidNid(ruim.getSid(), ruim.getNid()); |
| mPrlVersion = ruim.getPrlVersion(); |
| mIsMinInfoReady = true; |
| } |
| updateOtaspState(); |
| } |
| // reload eri in case of IMSI changed |
| // eri.xml can be defined by mcc mnc |
| mPhone.prepareEri(); |
| // SID/NID/PRL is loaded. Poll service state |
| // again to update to the roaming state with |
| // the latest variables. |
| pollState(); |
| break; |
| case EVENT_SIM_RECORDS_LOADED: |
| updatePhoneObject(); |
| break; |
| case EVENT_ALL_DATA_DISCONNECTED: |
| int dds = SubscriptionManager.getDefaultDataSubId(); |
| ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this); |
| synchronized(this) { |
| if (mPendingRadioPowerOffAfterDataOff) { |
| if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); |
| hangupAndPowerOff(); |
| mPendingRadioPowerOffAfterDataOff = false; |
| } else { |
| log("EVENT_ALL_DATA_DISCONNECTED is stale"); |
| } |
| } |
| break; |
| default: |
| super.handleMessage(msg); |
| } |
| } |
| |
| /** |
| * Handle the result of one of the pollState()-related requests |
| */ |
| @Override |
| protected void handlePollStateResultMessage(int what, AsyncResult ar) { |
| if (what == EVENT_POLL_STATE_GPRS) { |
| String states[] = (String[])ar.result; |
| if (DBG) { |
| log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" + |
| states.length + " states=" + states); |
| } |
| |
| int type = 0; |
| int regState = -1; |
| if (states.length > 0) { |
| try { |
| regState = Integer.parseInt(states[0]); |
| |
| // states[3] (if present) is the current radio technology |
| if (states.length >= 4 && states[3] != null) { |
| type = Integer.parseInt(states[3]); |
| } |
| } catch (NumberFormatException ex) { |
| loge("handlePollStateResultMessage: error parsing GprsRegistrationState: " |
| + ex); |
| } |
| if (states.length >= 10) { |
| int mcc; |
| int mnc; |
| int tac; |
| int pci; |
| int eci; |
| int csgid; |
| String operatorNumeric = null; |
| |
| try { |
| operatorNumeric = mNewSS.getOperatorNumeric(); |
| mcc = Integer.parseInt(operatorNumeric.substring(0,3)); |
| } catch (Exception e) { |
| try { |
| operatorNumeric = mSS.getOperatorNumeric(); |
| mcc = Integer.parseInt(operatorNumeric.substring(0,3)); |
| } catch (Exception ex) { |
| loge("handlePollStateResultMessage: bad mcc operatorNumeric=" + |
| operatorNumeric + " ex=" + ex); |
| operatorNumeric = ""; |
| mcc = Integer.MAX_VALUE; |
| } |
| } |
| try { |
| mnc = Integer.parseInt(operatorNumeric.substring(3)); |
| } catch (Exception e) { |
| loge("handlePollStateResultMessage: bad mnc operatorNumeric=" + |
| operatorNumeric + " e=" + e); |
| mnc = Integer.MAX_VALUE; |
| } |
| |
| // Use Integer#decode to be generous in what we receive and allow |
| // decimal, hex or octal values. |
| try { |
| tac = Integer.decode(states[6]); |
| } catch (Exception e) { |
| loge("handlePollStateResultMessage: bad tac states[6]=" + |
| states[6] + " e=" + e); |
| tac = Integer.MAX_VALUE; |
| } |
| try { |
| pci = Integer.decode(states[7]); |
| } catch (Exception e) { |
| loge("handlePollStateResultMessage: bad pci states[7]=" + |
| states[7] + " e=" + e); |
| pci = Integer.MAX_VALUE; |
| } |
| try { |
| eci = Integer.decode(states[8]); |
| } catch (Exception e) { |
| loge("handlePollStateResultMessage: bad eci states[8]=" + |
| states[8] + " e=" + e); |
| eci = Integer.MAX_VALUE; |
| } |
| try { |
| csgid = Integer.decode(states[9]); |
| } catch (Exception e) { |
| // FIX: Always bad so don't pollute the logs |
| // loge("handlePollStateResultMessage: bad csgid states[9]=" + |
| // states[9] + " e=" + e); |
| csgid = Integer.MAX_VALUE; |
| } |
| mNewCellIdentityLte = new CellIdentityLte(mcc, mnc, eci, pci, tac); |
| if (DBG) { |
| log("handlePollStateResultMessage: mNewLteCellIdentity=" + |
| mNewCellIdentityLte); |
| } |
| } |
| } |
| |
| mNewSS.setRilDataRadioTechnology(type); |
| int dataRegState = regCodeToServiceState(regState); |
| mNewSS.setDataRegState(dataRegState); |
| // voice roaming state in done while handling EVENT_POLL_STATE_REGISTRATION_CDMA |
| mNewSS.setDataRoaming(regCodeIsRoaming(regState)); |
| if (DBG) { |
| log("handlPollStateResultMessage: CdmaLteSST setDataRegState=" + dataRegState |
| + " regState=" + regState |
| + " dataRadioTechnology=" + type); |
| } |
| } else { |
| super.handlePollStateResultMessage(what, ar); |
| } |
| } |
| |
| @Override |
| public void pollState() { |
| mPollingContext = new int[1]; |
| mPollingContext[0] = 0; |
| |
| switch (mCi.getRadioState()) { |
| case RADIO_UNAVAILABLE: |
| mNewSS.setStateOutOfService(); |
| mNewCellLoc.setStateInvalid(); |
| setSignalStrengthDefaultValues(); |
| mGotCountryCode = false; |
| |
| pollStateDone(); |
| break; |
| |
| case RADIO_OFF: |
| mNewSS.setStateOff(); |
| mNewCellLoc.setStateInvalid(); |
| setSignalStrengthDefaultValues(); |
| mGotCountryCode = false; |
| |
| if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN |
| != mSS.getRilDataRadioTechnology()) { |
| pollStateDone(); |
| } |
| |
| default: |
| // Issue all poll-related commands at once, then count |
| // down the responses which are allowed to arrive |
| // out-of-order. |
| |
| mPollingContext[0]++; |
| // RIL_REQUEST_OPERATOR is necessary for CDMA |
| mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, mPollingContext)); |
| |
| mPollingContext[0]++; |
| // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA |
| mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, |
| mPollingContext)); |
| |
| mPollingContext[0]++; |
| // RIL_REQUEST_DATA_REGISTRATION_STATE |
| mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, |
| mPollingContext)); |
| break; |
| } |
| } |
| |
| @Override |
| protected void pollStateDone() { |
| log("pollStateDone: lte 1 ss=[" + mSS + "] newSS=[" + mNewSS + "]"); |
| |
| if (mPhone.isMccMncMarkedAsNonRoaming(mNewSS.getOperatorNumeric()) || |
| mPhone.isSidMarkedAsNonRoaming(mNewSS.getSystemId())) { |
| log("pollStateDone: override - marked as non-roaming."); |
| mNewSS.setVoiceRoaming(false); |
| mNewSS.setDataRoaming(false); |
| mNewSS.setCdmaEriIconIndex(EriInfo.ROAMING_INDICATOR_OFF); |
| } else if (mPhone.isMccMncMarkedAsRoaming(mNewSS.getOperatorNumeric()) || |
| mPhone.isSidMarkedAsRoaming(mNewSS.getSystemId())) { |
| log("pollStateDone: override - marked as roaming."); |
| mNewSS.setVoiceRoaming(true); |
| mNewSS.setDataRoaming(true); |
| mNewSS.setCdmaEriIconIndex(EriInfo.ROAMING_INDICATOR_ON); |
| mNewSS.setCdmaEriIconMode(EriInfo.ROAMING_ICON_MODE_NORMAL); |
| } |
| |
| if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) { |
| mNewSS.setVoiceRoaming(true); |
| mNewSS.setDataRoaming(true); |
| } |
| |
| useDataRegStateForDataOnlyDevices(); |
| |
| boolean hasRegistered = mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE |
| && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; |
| |
| boolean hasDeregistered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE |
| && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; |
| |
| boolean hasCdmaDataConnectionAttached = |
| mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE |
| && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; |
| |
| boolean hasCdmaDataConnectionDetached = |
| mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE |
| && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; |
| |
| boolean hasCdmaDataConnectionChanged = |
| mSS.getDataRegState() != mNewSS.getDataRegState(); |
| |
| boolean hasVoiceRadioTechnologyChanged = mSS.getRilVoiceRadioTechnology() |
| != mNewSS.getRilVoiceRadioTechnology(); |
| |
| boolean hasDataRadioTechnologyChanged = mSS.getRilDataRadioTechnology() |
| != mNewSS.getRilDataRadioTechnology(); |
| |
| boolean hasChanged = !mNewSS.equals(mSS); |
| |
| boolean hasVoiceRoamingOn = !mSS.getVoiceRoaming() && mNewSS.getVoiceRoaming(); |
| |
| boolean hasVoiceRoamingOff = mSS.getVoiceRoaming() && !mNewSS.getVoiceRoaming(); |
| |
| boolean hasDataRoamingOn = !mSS.getDataRoaming() && mNewSS.getDataRoaming(); |
| |
| boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming(); |
| |
| boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc); |
| |
| resetServiceStateInIwlanMode(); |
| |
| boolean has4gHandoff = |
| mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE && |
| (((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && |
| (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) || |
| ((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD) && |
| (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE))); |
| |
| boolean hasMultiApnSupport = |
| (((mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) || |
| (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) && |
| ((mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && |
| (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD))); |
| |
| boolean hasLostMultiApnSupport = |
| ((mNewSS.getRilDataRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A) && |
| (mNewSS.getRilDataRadioTechnology() <= ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)); |
| |
| TelephonyManager tm = |
| (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE); |
| |
| if (DBG) { |
| log("pollStateDone:" |
| + " hasRegistered=" + hasRegistered |
| + " hasDeegistered=" + hasDeregistered |
| + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached |
| + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached |
| + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged |
| + " hasVoiceRadioTechnologyChanged= " + hasVoiceRadioTechnologyChanged |
| + " hasDataRadioTechnologyChanged=" + hasDataRadioTechnologyChanged |
| + " hasChanged=" + hasChanged |
| + " hasVoiceRoamingOn=" + hasVoiceRoamingOn |
| + " hasVoiceRoamingOff=" + hasVoiceRoamingOff |
| + " hasDataRoamingOn=" + hasDataRoamingOn |
| + " hasDataRoamingOff=" + hasDataRoamingOff |
| + " hasLocationChanged=" + hasLocationChanged |
| + " has4gHandoff = " + has4gHandoff |
| + " hasMultiApnSupport=" + hasMultiApnSupport |
| + " hasLostMultiApnSupport=" + hasLostMultiApnSupport); |
| } |
| // Add an event log when connection state changes |
| if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState() |
| || mSS.getDataRegState() != mNewSS.getDataRegState()) { |
| EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, mSS.getVoiceRegState(), |
| mSS.getDataRegState(), mNewSS.getVoiceRegState(), mNewSS.getDataRegState()); |
| } |
| |
| ServiceState tss; |
| tss = mSS; |
| mSS = mNewSS; |
| mNewSS = tss; |
| // clean slate for next time |
| mNewSS.setStateOutOfService(); |
| |
| CdmaCellLocation tcl = mCellLoc; |
| mCellLoc = mNewCellLoc; |
| mNewCellLoc = tcl; |
| |
| mNewSS.setStateOutOfService(); // clean slate for next time |
| |
| if (hasVoiceRadioTechnologyChanged) { |
| updatePhoneObject(); |
| } |
| |
| if (hasDataRadioTechnologyChanged) { |
| tm.setDataNetworkTypeForPhone(mPhone.getPhoneId(), mSS.getRilDataRadioTechnology()); |
| |
| if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN |
| == mSS.getRilDataRadioTechnology()) { |
| log("pollStateDone: IWLAN enabled"); |
| } |
| } |
| |
| if (hasRegistered) { |
| mNetworkAttachedRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasChanged) { |
| boolean hasBrandOverride = mUiccController.getUiccCard(getPhoneId()) == null ? false : |
| (mUiccController.getUiccCard(getPhoneId()).getOperatorBrandOverride() != null); |
| if (!hasBrandOverride && (mCi.getRadioState().isOn()) && (mPhone.isEriFileLoaded()) && |
| (mSS.getRilVoiceRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_LTE || |
| mPhone.getContext().getResources().getBoolean(com.android.internal.R. |
| bool.config_LTE_eri_for_network_name))) { |
| // Only when CDMA is in service, ERI will take effect |
| String eriText = mSS.getOperatorAlphaLong(); |
| // Now the CDMAPhone sees the new ServiceState so it can get the |
| // new ERI text |
| if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { |
| eriText = mPhone.getCdmaEriText(); |
| } else if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF) { |
| eriText = (mIccRecords != null) ? mIccRecords.getServiceProviderName() : null; |
| if (TextUtils.isEmpty(eriText)) { |
| // Sets operator alpha property by retrieving from |
| // build-time system property |
| eriText = SystemProperties.get("ro.cdma.home.operator.alpha"); |
| } |
| } else if (mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE) { |
| // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used |
| // for mRegistrationState 0,2,3 and 4 |
| eriText = mPhone.getContext() |
| .getText(com.android.internal.R.string.roamingTextSearching).toString(); |
| } |
| mSS.setOperatorAlphaLong(eriText); |
| } |
| |
| if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY && |
| mIccRecords != null && (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE)) { |
| // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches |
| // one configured in SIM, use operator name from CSIM record. |
| boolean showSpn = |
| ((RuimRecords)mIccRecords).getCsimSpnDisplayCondition(); |
| int iconIndex = mSS.getCdmaEriIconIndex(); |
| |
| if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) && |
| isInHomeSidNid(mSS.getSystemId(), mSS.getNetworkId()) && |
| mIccRecords != null) { |
| mSS.setOperatorAlphaLong(mIccRecords.getServiceProviderName()); |
| } |
| } |
| |
| String operatorNumeric; |
| |
| tm.setNetworkOperatorNameForPhone(mPhone.getPhoneId(), mSS.getOperatorAlphaLong()); |
| |
| String prevOperatorNumeric = tm.getNetworkOperatorForPhone(mPhone.getPhoneId()); |
| operatorNumeric = mSS.getOperatorNumeric(); |
| // try to fix the invalid Operator Numeric |
| if (isInvalidOperatorNumeric(operatorNumeric)) { |
| int sid = mSS.getSystemId(); |
| operatorNumeric = fixUnknownMcc(operatorNumeric, sid); |
| } |
| tm.setNetworkOperatorNumericForPhone(mPhone.getPhoneId(), operatorNumeric); |
| updateCarrierMccMncConfiguration(operatorNumeric, |
| prevOperatorNumeric, mPhone.getContext()); |
| |
| if (isInvalidOperatorNumeric(operatorNumeric)) { |
| if (DBG) log("operatorNumeric is null"); |
| tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), ""); |
| mGotCountryCode = false; |
| } else { |
| String isoCountryCode = ""; |
| String mcc = operatorNumeric.substring(0, 3); |
| try { |
| isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric |
| .substring(0, 3))); |
| } catch (NumberFormatException ex) { |
| loge("countryCodeForMcc error" + ex); |
| } catch (StringIndexOutOfBoundsException ex) { |
| loge("countryCodeForMcc error" + ex); |
| } |
| |
| tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), isoCountryCode); |
| mGotCountryCode = true; |
| |
| setOperatorIdd(operatorNumeric); |
| |
| if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric, |
| mNeedFixZone)) { |
| fixTimeZone(isoCountryCode); |
| } |
| } |
| |
| tm.setNetworkRoamingForPhone(mPhone.getPhoneId(), |
| (mSS.getVoiceRoaming() || mSS.getDataRoaming())); |
| |
| updateSpnDisplay(); |
| setRoamingType(mSS); |
| log("Broadcasting ServiceState : " + mSS); |
| mPhone.notifyServiceStateChanged(mSS); |
| } |
| |
| if (hasCdmaDataConnectionAttached || has4gHandoff) { |
| mAttachedRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasCdmaDataConnectionDetached) { |
| mDetachedRegistrants.notifyRegistrants(); |
| } |
| |
| if ((hasCdmaDataConnectionChanged || hasDataRadioTechnologyChanged)) { |
| notifyDataRegStateRilRadioTechnologyChanged(); |
| if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN |
| == mSS.getRilDataRadioTechnology()) { |
| mPhone.notifyDataConnection(Phone.REASON_IWLAN_AVAILABLE); |
| } else { |
| mPhone.notifyDataConnection(null); |
| } |
| } |
| |
| if (hasVoiceRoamingOn) { |
| mVoiceRoamingOnRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasVoiceRoamingOff) { |
| mVoiceRoamingOffRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasDataRoamingOn) { |
| mDataRoamingOnRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasDataRoamingOff) { |
| mDataRoamingOffRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasLocationChanged) { |
| mPhone.notifyLocationChanged(); |
| } |
| |
| ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>(); |
| synchronized(mCellInfo) { |
| CellInfoLte cil = (CellInfoLte)mCellInfo; |
| |
| boolean cidChanged = ! mNewCellIdentityLte.equals(mLasteCellIdentityLte); |
| if (hasRegistered || hasDeregistered || cidChanged) { |
| // TODO: Handle the absence of LteCellIdentity |
| long timeStamp = SystemClock.elapsedRealtime() * 1000; |
| boolean registered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; |
| mLasteCellIdentityLte = mNewCellIdentityLte; |
| |
| cil.setRegistered(registered); |
| cil.setCellIdentity(mLasteCellIdentityLte); |
| if (DBG) { |
| log("pollStateDone: hasRegistered=" + hasRegistered + |
| " hasDeregistered=" + hasDeregistered + |
| " cidChanged=" + cidChanged + |
| " mCellInfo=" + mCellInfo); |
| } |
| arrayCi.add(mCellInfo); |
| } |
| mPhoneBase.notifyCellInfo(arrayCi); |
| } |
| } |
| |
| @Override |
| protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) { |
| if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { |
| isGsm = true; |
| } |
| boolean ssChanged = super.onSignalStrengthResult(ar, isGsm); |
| |
| synchronized (mCellInfo) { |
| if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { |
| mCellInfoLte.setTimeStamp(SystemClock.elapsedRealtime() * 1000); |
| mCellInfoLte.setTimeStampType(CellInfo.TIMESTAMP_TYPE_JAVA_RIL); |
| mCellInfoLte.getCellSignalStrength() |
| .initialize(mSignalStrength,SignalStrength.INVALID); |
| } |
| if (mCellInfoLte.getCellIdentity() != null) { |
| ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>(); |
| arrayCi.add(mCellInfoLte); |
| mPhoneBase.notifyCellInfo(arrayCi); |
| } |
| } |
| return ssChanged; |
| } |
| |
| @Override |
| public boolean isConcurrentVoiceAndDataAllowed() { |
| // Using the Conncurrent Service Supported flag for CdmaLte devices. |
| return mSS.getCssIndicator() == 1; |
| } |
| |
| /** |
| * Check whether the specified SID and NID pair appears in the HOME SID/NID list |
| * read from NV or SIM. |
| * |
| * @return true if provided sid/nid pair belongs to operator's home network. |
| */ |
| private boolean isInHomeSidNid(int sid, int nid) { |
| // if SID/NID is not available, assume this is home network. |
| if (isSidsAllZeros()) return true; |
| |
| // length of SID/NID shold be same |
| if (mHomeSystemId.length != mHomeNetworkId.length) return true; |
| |
| if (sid == 0) return true; |
| |
| for (int i = 0; i < mHomeSystemId.length; i++) { |
| // Use SID only if NID is a reserved value. |
| // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2) |
| if ((mHomeSystemId[i] == sid) && |
| ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) || |
| (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) { |
| return true; |
| } |
| } |
| // SID/NID are not in the list. So device is not in home network |
| return false; |
| } |
| |
| /** |
| * TODO: Remove when we get new ril/modem for Galaxy Nexus. |
| * |
| * @return all available cell information, the returned List maybe empty but never null. |
| */ |
| @Override |
| public List<CellInfo> getAllCellInfo() { |
| if (mCi.getRilVersion() >= 8) { |
| return super.getAllCellInfo(); |
| } else { |
| ArrayList<CellInfo> arrayList = new ArrayList<CellInfo>(); |
| CellInfo ci; |
| synchronized(mCellInfo) { |
| arrayList.add(mCellInfoLte); |
| } |
| if (DBG) log ("getAllCellInfo: arrayList=" + arrayList); |
| return arrayList; |
| } |
| } |
| |
| @Override |
| protected UiccCardApplication getUiccCardApplication() { |
| return mUiccController.getUiccCardApplication(((CDMALTEPhone)mPhone). |
| getPhoneId(), UiccController.APP_FAM_3GPP2); |
| } |
| |
| protected void updateCdmaSubscription() { |
| mCi.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); |
| } |
| |
| /** |
| * Clean up existing voice and data connection then turn off radio power. |
| * |
| * Hang up the existing voice calls to decrease call drop rate. |
| */ |
| @Override |
| public void powerOffRadioSafely(DcTrackerBase dcTracker) { |
| synchronized (this) { |
| if (!mPendingRadioPowerOffAfterDataOff) { |
| int dds = SubscriptionManager.getDefaultDataSubId(); |
| // To minimize race conditions we call cleanUpAllConnections on |
| // both if else paths instead of before this isDisconnected test. |
| if (dcTracker.isDisconnected() |
| && (dds == mPhone.getSubId() |
| || (dds != mPhone.getSubId() |
| && ProxyController.getInstance().isDataDisconnected(dds)))) { |
| // To minimize race conditions we do this after isDisconnected |
| dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF); |
| if (DBG) log("Data disconnected, turn off radio right away."); |
| hangupAndPowerOff(); |
| } else { |
| dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF); |
| if (dds != mPhone.getSubId() |
| && !ProxyController.getInstance().isDataDisconnected(dds)) { |
| if (DBG) log("Data is active on DDS. Wait for all data disconnect"); |
| // Data is not disconnected on DDS. Wait for the data disconnect complete |
| // before sending the RADIO_POWER off. |
| ProxyController.getInstance().registerForAllDataDisconnected(dds, this, |
| EVENT_ALL_DATA_DISCONNECTED, null); |
| mPendingRadioPowerOffAfterDataOff = true; |
| } |
| Message msg = Message.obtain(this); |
| msg.what = EVENT_SET_RADIO_POWER_OFF; |
| msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; |
| if (sendMessageDelayed(msg, 30000)) { |
| if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio."); |
| mPendingRadioPowerOffAfterDataOff = true; |
| } else { |
| log("Cannot send delayed Msg, turn off radio right away."); |
| hangupAndPowerOff(); |
| mPendingRadioPowerOffAfterDataOff = false; |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void log(String s) { |
| Rlog.d(LOG_TAG, "[CdmaLteSST] " + s); |
| } |
| |
| @Override |
| protected void loge(String s) { |
| Rlog.e(LOG_TAG, "[CdmaLteSST] " + s); |
| } |
| |
| @Override |
| public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| pw.println("CdmaLteServiceStateTracker extends:"); |
| super.dump(fd, pw, args); |
| pw.println(" mCdmaLtePhone=" + mCdmaLtePhone); |
| } |
| } |