Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e076762 authored by Jack Yu's avatar Jack Yu Committed by Gerrit Code Review
Browse files

Merge changes from topic "switch_logging"

* changes:
  Improved PhoneSwitcher logging
  Fixed VCN network was not treated as internet
  Do not dynamically change MMTEL capability
  Fixed data leak after emergency call
  Optimized data retry
parents ca140b19 62bc5a9a
Loading
Loading
Loading
Loading
+13 −12
Original line number Diff line number Diff line
@@ -1314,8 +1314,6 @@ public class DataNetwork extends StateMachine {
                case EVENT_VOICE_CALL_STARTED:
                case EVENT_VOICE_CALL_ENDED:
                case EVENT_CSS_INDICATOR_CHANGED:
                    // We might entered non-VoPS network. Need to update the network capability to
                    // remove MMTEL capability.
                    updateSuspendState();
                    updateNetworkCapabilities();
                    break;
@@ -1493,8 +1491,6 @@ public class DataNetwork extends StateMachine {
                case EVENT_CSS_INDICATOR_CHANGED:
                case EVENT_VOICE_CALL_STARTED:
                case EVENT_VOICE_CALL_ENDED:
                    // We might entered non-VoPS network. Need to update the network capability to
                    // remove MMTEL capability.
                    updateSuspendState();
                    updateNetworkCapabilities();
                    break;
@@ -1828,14 +1824,13 @@ public class DataNetwork extends StateMachine {
            }
        }

        // If voice call is on-going, do not change MMTEL capability, which is an immutable
        // capability. Changing it will result in CS tearing down IMS network, and the voice
        // call will drop.
        if (shouldDelayImsTearDown() && mNetworkCapabilities != null
        // Once we set the MMTEL capability, we should never remove it because it's an immutable
        // capability defined by connectivity service. When the device enters from VoPS to non-VoPS,
        // we should perform grace tear down from data network controller if needed.
        if (mNetworkCapabilities != null
                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL)) {
            // Previous capability has MMTEL, so add it again.
            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
            log("Delayed IMS tear down. Reporting MMTEL capability for now.");
        } else {
            // Always add MMTEL capability on IMS network unless network explicitly indicates VoPS
            // not supported.
@@ -2491,7 +2486,7 @@ public class DataNetwork extends StateMachine {
    public boolean shouldDelayImsTearDown() {
        return mDataConfigManager.isImsDelayTearDownEnabled()
                && mNetworkCapabilities != null
                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL)
                && mPhone.getImsPhone() != null
                && mPhone.getImsPhone().getCallTracker().getState()
                != PhoneConstants.State.IDLE;
@@ -2990,12 +2985,18 @@ public class DataNetwork extends StateMachine {
                        NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
                && mNetworkCapabilities.hasCapability(
                        NetworkCapabilities.NET_CAPABILITY_TRUSTED)
                && mNetworkCapabilities.hasCapability(
                        NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
                && mNetworkCapabilities.hasCapability(
                        NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
    }

    /**
     * @return {@code true} if this network was setup for SUPL during emergency call. {@code false}
     * otherwise.
     */
    public boolean isEmergencySupl() {
        return mDataAllowedReason == DataAllowedReason.EMERGENCY_SUPL;
    }

    /**
     * Get precise data connection state
     *
+33 −5
Original line number Diff line number Diff line
@@ -932,8 +932,13 @@ public class DataNetworkController extends Handler {
                        + DataUtils.networkCapabilityToString(capability) + " preferred on "
                        + AccessNetworkConstants.transportTypeToString(preferredTransport));
                DataNetworkController.this.onEvaluatePreferredTransport(capability);
                if (!hasMessages(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS)) {
                    sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS,
                            DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED));
                } else {
                    log("onPreferredTransportChanged: Skipped evaluating unsatisfied network "
                            + "requests because another evaluation was already scheduled.");
                }
            }
        });

@@ -1653,6 +1658,31 @@ public class DataNetworkController extends Handler {
            }
        }

        // If the data network is IMS that supports voice call, and has MMTEL request (client
        // specified VoPS is required.)
        if (dataNetwork.getAttachedNetworkRequestList().get(
                new int[]{NetworkCapabilities.NET_CAPABILITY_MMTEL}) != null) {
            // When reaching here, it means the network supports MMTEL, and also has MMTEL request
            // attached to it.
            if (!dataNetwork.shouldDelayImsTearDown()) {
                if (dataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
                    NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo(
                            NetworkRegistrationInfo.DOMAIN_PS,
                            AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
                    if (nri != null) {
                        DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
                        if (dsri != null && dsri.getVopsSupportInfo() != null
                                && !dsri.getVopsSupportInfo().isVopsSupported()) {
                            evaluation.addDataDisallowedReason(
                                    DataDisallowedReason.VOPS_NOT_SUPPORTED);
                        }
                    }
                }
            } else {
                log("Ignored VoPS check due to delay IMS tear down until call ends.");
            }
        }

        // Check if data is disabled
        boolean dataDisabled = false;
        if (!mDataSettingsManager.isDataEnabled()) {
@@ -1720,9 +1750,7 @@ public class DataNetworkController extends Handler {
            // If there are reasons we should tear down the network, check if those are hard reasons
            // or soft reasons. In some scenarios, we can make exceptions if they are soft
            // disallowed reasons.
            if ((mPhone.isInEmergencyCall() || mPhone.isInEcm())
                    && dataNetwork.getNetworkCapabilities().hasCapability(
                            NetworkCapabilities.NET_CAPABILITY_SUPL)) {
            if ((mPhone.isInEmergencyCall() || mPhone.isInEcm()) && dataNetwork.isEmergencySupl()) {
                // Check if it's SUPL during emergency call.
                evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_SUPL);
            } else if (!dataNetwork.getNetworkCapabilities().hasCapability(
+68 −6
Original line number Diff line number Diff line
@@ -312,7 +312,7 @@ public class PhoneSwitcher extends Handler {

    protected RadioConfig mRadioConfig;

    private static final int MAX_LOCAL_LOG_LINES = 32;
    private static final int MAX_LOCAL_LOG_LINES = 256;

    // Default timeout value of network validation in millisecond.
    private final static int DEFAULT_VALIDATION_EXPIRATION_TIME = 2000;
@@ -958,7 +958,7 @@ public class PhoneSwitcher extends Handler {
                mPrioritizedDcRequests.add(dcRequest);
                Collections.sort(mPrioritizedDcRequests);
                onEvaluate(REQUESTS_CHANGED, "netRequest");
                log("Added DcRequest, size: " + mPrioritizedDcRequests.size());
                if (VDBG) log("Added DcRequest, size: " + mPrioritizedDcRequests.size());
            }
        }
    }
@@ -979,7 +979,7 @@ public class PhoneSwitcher extends Handler {
            if (mPrioritizedDcRequests.remove(dcRequest)) {
                onEvaluate(REQUESTS_CHANGED, "netReleased");
                collectReleaseNetworkMetrics(networkRequest);
                log("Removed DcRequest, size: " + mPrioritizedDcRequests.size());
                if (VDBG) log("Removed DcRequest, size: " + mPrioritizedDcRequests.size());
            }
        }
    }
@@ -1264,7 +1264,7 @@ public class PhoneSwitcher extends Handler {

    protected void sendRilCommands(int phoneId) {
        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
            log("sendRilCommands: skip dds switch due to invalid phoneid=" + phoneId);
            log("sendRilCommands: skip dds switch due to invalid phoneId=" + phoneId);
            return;
        }

@@ -1674,8 +1674,54 @@ public class PhoneSwitcher extends Handler {
        mLocalLog.log(l);
    }

    /**
     * Convert data switch reason into string.
     *
     * @param reason The switch reason.
     * @return The switch reason in string format.
     */
    private static @NonNull String switchReasonToString(int reason) {
        switch(reason) {
            case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN:
                return "UNKNOWN";
            case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL:
                return "MANUAL";
            case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL:
                return "IN_CALL";
            case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_CBRS:
                return "CBRS";
            default: return "UNKNOWN(" + reason + ")";
        }
    }

    /**
     * Concert switching state to string
     *
     * @param state The switching state.
     * @return The switching state in string format.
     */
    private static @NonNull String switchStateToString(int state) {
        switch(state) {
            case TelephonyEvent.EventState.EVENT_STATE_UNKNOWN:
                return "UNKNOWN";
            case TelephonyEvent.EventState.EVENT_STATE_START:
                return "START";
            case TelephonyEvent.EventState.EVENT_STATE_END:
                return "END";
            default: return "UNKNOWN(" + state + ")";
        }
    }

    /**
     * Log data switch event
     *
     * @param subId Subscription index.
     * @param state The switching state.
     * @param reason The switching reason.
     */
    private void logDataSwitchEvent(int subId, int state, int reason) {
        log("logDataSwitchEvent subId " + subId + " state " + state + " reason " + reason);
        log("Data switch event. subId=" + subId + ", state=" + switchStateToString(state)
                + ", reason=" + switchReasonToString(reason));
        DataSwitch dataSwitch = new DataSwitch();
        dataSwitch.state = state;
        dataSwitch.reason = reason;
@@ -1708,6 +1754,7 @@ public class PhoneSwitcher extends Handler {
    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
        pw.println("PhoneSwitcher:");
        pw.increaseIndent();
        Calendar c = Calendar.getInstance();
        for (int i = 0; i < mActiveModemCount; i++) {
            PhoneState ps = mPhoneStates[i];
@@ -1716,14 +1763,29 @@ public class PhoneSwitcher extends Handler {
                    (ps.lastRequested == 0 ? "never" :
                     String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)));
        }
        pw.println("mPreferredDataPhoneId=" + mPreferredDataPhoneId);
        pw.println("mPreferredDataSubId=" + mPreferredDataSubId.get());
        pw.println("DefaultDataSubId=" + mSubscriptionController.getDefaultDataSubId());
        pw.println("DefaultDataPhoneId=" + mSubscriptionController.getPhoneId(
                mSubscriptionController.getDefaultDataSubId()));
        pw.println("mPrimaryDataSubId=" + mPrimaryDataSubId);
        pw.println("mOpptDataSubId=" + mOpptDataSubId);
        pw.println("mIsRegisteredForImsRadioTechChange=" + mIsRegisteredForImsRadioTechChange);
        pw.println("mPendingSwitchNeedValidation=" + mPendingSwitchNeedValidation);
        pw.println("mMaxDataAttachModemCount=" + mMaxDataAttachModemCount);
        pw.println("mActiveModemCount=" + mActiveModemCount);
        pw.println("mPhoneIdInVoiceCall=" + mPhoneIdInVoiceCall);
        pw.println("mCurrentDdsSwitchFailure=" + mCurrentDdsSwitchFailure);
        pw.println("Local logs:");
        pw.increaseIndent();
        mLocalLog.dump(fd, pw, args);
        pw.decreaseIndent();
        pw.decreaseIndent();
    }

    private boolean isAnyVoiceCallActiveOnDevice() {
        boolean ret = mPhoneIdInVoiceCall != SubscriptionManager.INVALID_PHONE_INDEX;
        log("isAnyVoiceCallActiveOnDevice: " + ret);
        if (VDBG) log("isAnyVoiceCallActiveOnDevice: " + ret);
        return ret;
    }

+9 −2
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ public class TelephonyNetworkFactory extends NetworkFactory {
    public final String LOG_TAG;
    protected static final boolean DBG = true;

    private static final int REQUEST_LOG_SIZE = 32;
    private static final int REQUEST_LOG_SIZE = 256;

    private static final int ACTION_NO_OP   = 0;
    private static final int ACTION_REQUEST = 1;
@@ -306,6 +306,7 @@ public class TelephonyNetworkFactory extends NetworkFactory {

    // apply or revoke requests if our active-ness changes
    private void onActivePhoneSwitch() {
        logl("onActivePhoneSwitch");
        for (Map.Entry<TelephonyNetworkRequest, Integer> entry : mNetworkRequests.entrySet()) {
            TelephonyNetworkRequest networkRequest = entry.getKey();
            boolean applied = entry.getValue() != AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
@@ -342,7 +343,7 @@ public class TelephonyNetworkFactory extends NetworkFactory {
        final int newSubscriptionId = mSubscriptionController.getSubIdUsingPhoneId(
                mPhone.getPhoneId());
        if (mSubscriptionId != newSubscriptionId) {
            if (DBG) log("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId);
            if (DBG) logl("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId);
            mSubscriptionId = newSubscriptionId;
            setCapabilityFilter(makeNetworkFilter(mSubscriptionId));
        }
@@ -539,6 +540,8 @@ public class TelephonyNetworkFactory extends NetworkFactory {
     */
    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
        pw.println("TelephonyNetworkFactory-" + mPhone.getPhoneId());
        pw.increaseIndent();
        pw.println("Network Requests:");
        pw.increaseIndent();
        for (Map.Entry<TelephonyNetworkRequest, Integer> entry : mNetworkRequests.entrySet()) {
@@ -547,7 +550,11 @@ public class TelephonyNetworkFactory extends NetworkFactory {
            pw.println(nr + (transport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID
                    ? (" applied on " + transport) : " not applied"));
        }
        pw.decreaseIndent();
        pw.print("Local logs:");
        pw.increaseIndent();
        mLocalLog.dump(fd, pw, args);
        pw.decreaseIndent();
        pw.decreaseIndent();
    }
}
+149 −6
Original line number Diff line number Diff line
@@ -2246,15 +2246,13 @@ public class DataNetworkControllerTest extends TelephonyTest {
        mDataNetworkControllerUT.addNetworkRequest(tnr);
        processAllMessages();

        // VCN managed network won't trigger onInternetDataNetworkConnected.
        // DataNetwork.isInternetSupported() is false for VCN managed network.
        verify(mMockedDataNetworkControllerCallback, never())
        verify(mMockedDataNetworkControllerCallback)
                .onInternetDataNetworkConnected(any());
        List<DataNetwork> dataNetworks = getDataNetworks();
        assertThat(dataNetworks).hasSize(1);
        assertThat(dataNetworks.get(0).getNetworkCapabilities().hasCapability(
                NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)).isFalse();
        assertThat(dataNetworks.get(0).isInternetSupported()).isFalse();
        assertThat(dataNetworks.get(0).isInternetSupported()).isTrue();
        assertThat(dataNetworks.get(0).getNetworkCapabilities().hasCapability(
                NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
    }
@@ -2636,6 +2634,25 @@ public class DataNetworkControllerTest extends TelephonyTest {
        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
    }

    @Test
    public void testEmergencyCallDataDisabled() throws Exception {
        doReturn(true).when(mPhone).isInEmergencyCall();
        mDataNetworkControllerUT.addNetworkRequest(
                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET));
        processAllMessages();

        verifyInternetConnected();

        // Data disabled
        mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled(
                TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName());
        processAllMessages();

        // Make sure internet is not connected. (Previously it has a bug due to incorrect logic
        // to determine it's for emergency SUPL).
        verifyAllDataDisconnected();
    }

    @Test
    public void testDataActivity() {
        doReturn(TelephonyManager.DATA_ACTIVITY_IN).when(mLinkBandwidthEstimator).getDataActivity();
@@ -2811,7 +2828,7 @@ public class DataNetworkControllerTest extends TelephonyTest {
                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS));
        processAllMessages();

        // Even though the network request deos not have MMTEL, but the network support it, so
        // Even though the network request does not have MMTEL, but the network support it, so
        // the network capabilities should still have MMTEL.
        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
                NetworkCapabilities.NET_CAPABILITY_MMTEL);
@@ -2825,11 +2842,137 @@ public class DataNetworkControllerTest extends TelephonyTest {
                any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(),
                any(), any(), anyBoolean(), any(Message.class));

        // The IMS network should only have IMS, but no MMTEL.
        // The IMS network should still have IMS and MMTEL.
        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS);
        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMTEL);
    }

    @Test
    public void testMmtelImsDataNetworkMovingToNonVops() throws Exception {
        ServiceState ss = new ServiceState();

        // VoPS network
        DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true,
                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
                        LteVopsSupportInfo.LTE_STATUS_SUPPORTED));

        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
                .setDataSpecificInfo(dsri)
                .build());

        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
                .build());

        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
                .build());
        doReturn(ss).when(mSST).getServiceState();
        doReturn(ss).when(mPhone).getServiceState();

        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);

        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
        processAllMessages();

        // Bring up the IMS network that does require MMTEL
        mDataNetworkControllerUT.addNetworkRequest(
                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS,
                        NetworkCapabilities.NET_CAPABILITY_MMTEL));
        processAllMessages();

        // the network capabilities should have IMS and MMTEL.
        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
                NetworkCapabilities.NET_CAPABILITY_MMTEL);

        ss = new ServiceState();
        // Non VoPS network
        dsri = new DataSpecificRegistrationInfo(8, false, true, true,
                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
                        LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED));

        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
                .setDataSpecificInfo(dsri)
                .build());

        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
                .build());

        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
                .build());
        doReturn(ss).when(mSST).getServiceState();
        doReturn(ss).when(mPhone).getServiceState();

        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
        processAllMessages();

        // The IMS network should be torn down by data network controller.
        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
    }

    @Test
    public void testVoPStoNonVoPSDelayImsTearDown() throws Exception {
        mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL,
                true);
        carrierConfigChanged();

        // VoPS supported
        DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true,
                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
                        LteVopsSupportInfo.LTE_STATUS_SUPPORTED));
        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);

        mDataNetworkControllerUT.addNetworkRequest(
                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS,
                        NetworkCapabilities.NET_CAPABILITY_MMTEL));
        processAllMessages();
        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS);

        doReturn(PhoneConstants.State.OFFHOOK).when(mCT).getState();

        dsri = new DataSpecificRegistrationInfo(8, false, true, true,
                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
                        LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED));
        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);

        // Make sure IMS is still connected.
        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
                NetworkCapabilities.NET_CAPABILITY_MMTEL);

        // Call ends
        doReturn(PhoneConstants.State.IDLE).when(mCT).getState();
        mDataNetworkControllerUT.obtainMessage(18/*EVENT_VOICE_CALL_ENDED*/).sendToTarget();
        processAllMessages();

        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
    }

    @Test
    public void testDeactivateDataOnOldHal() throws Exception {
        doAnswer(invocation -> {
Loading