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

Commit b0f40da6 authored by Sarah Chin's avatar Sarah Chin Committed by Automerger Merge Worker
Browse files

Merge "Update logic for enterprise connections" am: 5e2cf5f5

Original change: https://android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/1654427

Change-Id: I105726e381e16b8064691b63fed3557a71d2ea4e
parents 1f29315b 5e2cf5f5
Loading
Loading
Loading
Loading
+74 −22
Original line number Diff line number Diff line
@@ -563,7 +563,9 @@ public class DataConnection extends StateMachine {
        ERROR_RADIO_NOT_AVAILABLE,
        ERROR_INVALID_ARG,
        ERROR_STALE,
        ERROR_DATA_SERVICE_SPECIFIC_ERROR;
        ERROR_DATA_SERVICE_SPECIFIC_ERROR,
        ERROR_DUPLICATE_CID,
        ERROR_NO_DEFAULT_CONNECTION;

        public int mFailCause;

@@ -636,7 +638,7 @@ public class DataConnection extends StateMachine {
    public void updateQosParameters(final @Nullable DataCallResponse response) {
        if (response == null) {
            mDefaultQos = null;
            mQosBearerSessions = null;
            mQosBearerSessions.clear();
            return;
        }

@@ -879,7 +881,7 @@ public class DataConnection extends StateMachine {
        String dnn = null;
        String osAppId = null;
        if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
            // TODO: update osAppId to use NetworkCapability API once it's available
            // TODO(b/181916712): update osAppId to use NetworkCapability API once it's available
            osAppId = ApnSetting.getApnTypesStringFromBitmask(mApnSetting.getApnTypeBitmask());
        } else {
            dnn = mApnSetting.getApnName();
@@ -1308,6 +1310,7 @@ public class DataConnection extends StateMachine {
        mApnContexts.clear();
        mApnSetting = null;
        mUnmeteredUseOnly = false;
        mEnterpriseUse = false;
        mRestrictedNetworkOverride = false;
        mDcFailCause = DataFailCause.NONE;
        mDisabledApnTypeBitMask = 0;
@@ -1319,6 +1322,10 @@ public class DataConnection extends StateMachine {
        mIsSuspended = false;
        mHandoverState = HANDOVER_STATE_IDLE;
        mHandoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN;
        mSliceInfo = null;
        mDefaultQos = null;
        mQosBearerSessions.clear();
        mTrafficDescriptors.clear();
    }

    /**
@@ -1351,6 +1358,14 @@ public class DataConnection extends StateMachine {
                result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR;
                result.mFailCause = DataFailCause.getFailCause(response.getCause());
            }
        } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE
                && mDcController.getActiveDcByCid(response.getId()) != null) {
            if (DBG) log("DataConnection already exists for cid: " + response.getId());
            result = SetupResult.ERROR_DUPLICATE_CID;
        } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE
                && !mDcController.isDefaultDataActive()) {
            if (DBG) log("No default data connection currently active");
            result = SetupResult.ERROR_NO_DEFAULT_CONNECTION;
        } else {
            if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse");
            mCid = response.getId();
@@ -1615,6 +1630,14 @@ public class DataConnection extends StateMachine {
     */
    private boolean mRestrictedNetworkOverride = false;

    /**
     * Indicates if this data connection supports enterprise use. Note that this flag should be
     * populated when data becomes active. Once it is set, the value cannot be changed because
     * setting it will cause this data connection to lose immutable network capabilities, which can
     * cause issues in connectivity service.
     */
    private boolean mEnterpriseUse = false;

    /**
     * Check if this data connection should be restricted. We should call this when data connection
     * becomes active, or when we want to re-evaluate the conditions to decide if we need to
@@ -1622,7 +1645,6 @@ public class DataConnection extends StateMachine {
     *
     * @return True if this data connection needs to be restricted.
     */

    private boolean shouldRestrictNetwork() {
        // first, check if there is any network request that containing restricted capability
        // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request)
@@ -1692,6 +1714,25 @@ public class DataConnection extends StateMachine {
        return true;
    }

    /**
     * Check if this data connection supports enterprise use. We call this when the data connection
     * becomes active or when we want to reevaluate the conditions to decide if we need to update
     * the network agent capabilities.
     *
     * @return True if this data connection supports enterprise use.
     */
    private boolean isEnterpriseUse() {
        // TODO(b/181916712): update osAppId to use NetworkCapability API once it's available
        boolean enterpriseTrafficDescriptor = mTrafficDescriptors
                .stream()
                .anyMatch(td -> td.getOsAppId() != null && td.getOsAppId().equals(
                        ApnSetting.TYPE_ENTERPRISE_STRING));
        boolean enterpriseApnContext = mApnContexts.keySet()
                .stream()
                .anyMatch(ac -> ac.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE);
        return enterpriseTrafficDescriptor || enterpriseApnContext;
    }

    /**
     * Get the network capabilities for this data connection.
     *
@@ -1701,8 +1742,9 @@ public class DataConnection extends StateMachine {
        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
        boolean hasInternet = false;
        boolean unmeteredApns = false;

        if (mApnSetting != null) {
        if (mApnSetting != null && !mEnterpriseUse) {
            final String[] types = ApnSetting.getApnTypesStringFromBitmask(
                    mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask).split(",");
            for (String type : types) {
@@ -1776,11 +1818,15 @@ public class DataConnection extends StateMachine {
                builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
            }

            if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) {
                unmeteredApns = true;
            }
        }

        // Mark NOT_METERED in the following cases:
        // 1. All APNs in the APN settings are unmetered.
        // 2. The non-restricted data is intended for unmetered use only.
            if ((mUnmeteredUseOnly && !mRestrictedNetworkOverride)
                    || !ApnSettingUtils.isMetered(mApnSetting, mPhone)) {
        if (unmeteredApns || (mUnmeteredUseOnly && !mRestrictedNetworkOverride)) {
            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
        } else {
            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
@@ -1790,13 +1836,10 @@ public class DataConnection extends StateMachine {
        if (builder.build().deduceRestrictedCapability()) {
            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
        }
        }

        for (ApnContext ctx : mApnContexts.keySet()) {
            if (ctx.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
        if (mEnterpriseUse) {
            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
        }
        }

        if (mRestrictedNetworkOverride) {
            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
@@ -2529,6 +2572,12 @@ public class DataConnection extends StateMachine {
                                    DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN);
                            transitionTo(mInactiveState);
                            break;
                        case ERROR_DUPLICATE_CID:
                            // TODO (b/180988471): Properly handle the case when an existing cid is
                            // returned by tearing down the network agent if enterprise changed.
                        case ERROR_NO_DEFAULT_CONNECTION:
                            // TODO (b/180988471): Properly handle the case when a default data
                            // connection doesn't exist.
                        case ERROR_INVALID_ARG:
                            // The addresses given from the RIL are bad
                            tearDownData(cp);
@@ -2659,10 +2708,12 @@ public class DataConnection extends StateMachine {
            }

            mUnmeteredUseOnly = isUnmeteredUseOnly();
            mEnterpriseUse = isEnterpriseUse();

            if (DBG) {
                log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride
                        + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly);
                        + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly
                        + ", mEnterpriseUse = " + mEnterpriseUse);
            }

            // Always register a VcnNetworkPolicyChangeListener, regardless of whether this is a
@@ -3773,6 +3824,7 @@ public class DataConnection extends StateMachine {
        pw.println("mUserData=" + mUserData);
        pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride);
        pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly);
        pw.println("mEnterpriseUse=" + mEnterpriseUse);
        pw.println("mUnmeteredOverride=" + mUnmeteredOverride);
        pw.println("mCongestedOverride=" + mCongestedOverride);
        pw.println("mDownlinkBandwidth" + mDownlinkBandwidth);
+9 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.os.Message;
import android.os.RegistrantList;
import android.telephony.AccessNetworkConstants;
import android.telephony.DataFailCause;
import android.telephony.data.ApnSetting;
import android.telephony.data.DataCallResponse;

import com.android.internal.telephony.DctConstants;
@@ -161,6 +162,14 @@ public class DcController extends Handler {
        }
    }

    boolean isDefaultDataActive() {
        synchronized (mDcListAll) {
            return mDcListActiveByCid.values().stream()
                    .anyMatch(dc -> dc.getApnContexts().stream()
                            .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT));
        }
    }

    @Override
    public void handleMessage(Message msg) {
        AsyncResult ar;
+0 −9
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SignalThresholdInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.data.DataCallResponse;
import android.telephony.data.DataProfile;
import android.telephony.data.SliceInfo;
@@ -1216,14 +1215,6 @@ public class SimulatedCommands extends BaseCommands
            }
        }

        // Store different cids to simulate concurrent IMS and default data calls
        if ((dataProfile.getSupportedApnTypesBitmask() & ApnSetting.TYPE_IMS)
            == ApnSetting.TYPE_IMS) {
            mSetupDataCallResult.cid = 0;
        } else {
            mSetupDataCallResult.cid = 1;
        }

        DataCallResponse response = RIL.convertDataCallResult(mSetupDataCallResult);
        if (mDcSuccess) {
            resultSuccess(result, response);
+153 −17
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import static org.mockito.Mockito.verify;

import android.content.IntentFilter;
import android.content.pm.ServiceInfo;
import android.hardware.radio.V1_0.SetupDataCallResult;
import android.net.InetAddresses;
import android.net.KeepalivePacketData;
import android.net.LinkAddress;
@@ -86,6 +87,7 @@ import java.util.Arrays;
import java.util.Collections;

public class DataConnectionTest extends TelephonyTest {
    private static final int DEFAULT_DC_CID = 10;

    @Mock
    DcTesterFailBringUpAll mDcTesterFailBringUpAll;
@@ -96,9 +98,13 @@ public class DataConnectionTest extends TelephonyTest {
    @Mock
    ApnContext mApnContext;
    @Mock
    ApnContext mEnterpriseApnContext;
    @Mock
    DcFailBringUp mDcFailBringUp;
    @Mock
    DataCallSessionStats mDataCallSessionStats;
    @Mock
    DataConnection mDefaultDc;

    private DataConnection mDc;
    private DataConnectionTestHandler mDataConnectionTestHandler;
@@ -290,6 +296,7 @@ public class DataConnectionTest extends TelephonyTest {
                ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
        doReturn(mApn1).when(mApnContext).getApnSetting();
        doReturn(ApnSetting.TYPE_DEFAULT_STRING).when(mApnContext).getApnType();
        doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask();

        mDcFailBringUp.saveParameters(0, 0, -2);
        doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp();
@@ -353,8 +360,13 @@ public class DataConnectionTest extends TelephonyTest {
        return (boolean) method.invoke(mDc);
    }

    private SetupResult setLinkProperties(DataCallResponse response,
                                                         LinkProperties linkProperties)
    private boolean isEnterpriseUse() throws Exception {
        Method method = DataConnection.class.getDeclaredMethod("isEnterpriseUse");
        method.setAccessible(true);
        return (boolean) method.invoke(mDc);
    }

    private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties)
            throws Exception {
        Class[] cArgs = new Class[2];
        cArgs[0] = DataCallResponse.class;
@@ -374,9 +386,7 @@ public class DataConnectionTest extends TelephonyTest {
    @SmallTest
    public void testConnectEvent() throws Exception {
        testSanity();

        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
        waitForMs(200);
        connectEvent(true);

        verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class),
                eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null));
@@ -417,7 +427,7 @@ public class DataConnectionTest extends TelephonyTest {
                assertEquals(null, tdCaptor.getValue().getOsAppId());
            }
        }
        assertEquals("DcActiveState", getCurrentState().getName());
        assertTrue(mDc.isActive());

        assertEquals(mDc.getPduSessionId(), 1);
        assertEquals(3, mDc.getPcscfAddresses().length);
@@ -426,14 +436,86 @@ public class DataConnectionTest extends TelephonyTest {
        assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals));
    }

    @Test
    public void testConnectEventDuplicateContextIds() throws Exception {
        setUpDefaultData();

        // Create successful result with the same CID as default
        SetupDataCallResult result = new SetupDataCallResult();
        result.status = 0;
        result.suggestedRetryTime = -1;
        result.cid = DEFAULT_DC_CID;
        result.active = 2;
        result.type = "IP";
        result.ifname = FAKE_IFNAME;
        result.addresses = FAKE_ADDRESS;
        result.dnses = FAKE_DNS;
        result.gateways = FAKE_GATEWAY;
        result.pcscf = FAKE_PCSCF_ADDRESS;
        result.mtu = 1440;
        mSimulatedCommands.setDataCallResult(true, result);

        // Try to connect ENTERPRISE with the same CID as default
        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
        doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting();
        doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType();
        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask();

        // Verify that ENTERPRISE wasn't set up
        connectEvent(false);
        assertEquals("DcInactiveState", getCurrentState().getName());

        // Change the CID
        result.cid = DEFAULT_DC_CID + 1;
        mSimulatedCommands.setDataCallResult(true, result);

        // Verify that ENTERPRISE was set up
        connectEvent(true);
        assertTrue(mDc.getNetworkCapabilities().hasCapability(
                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
    }

    @Test
    public void testConnectEventNoDefaultData() throws Exception {
        assertFalse(mDefaultDc.isActive());

        // Try to connect ENTERPRISE when default data doesn't exist
        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
        doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting();
        doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType();
        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask();

        // Verify that ENTERPRISE wasn't set up
        connectEvent(false);
        assertEquals("DcInactiveState", getCurrentState().getName());

        // Set up default data
        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext);
        setUpDefaultData();

        // Verify that ENTERPRISE was set up
        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
        connectEvent(true);
        assertTrue(mDc.getNetworkCapabilities().hasCapability(
                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
    }

    private void setUpDefaultData() throws Exception {
        replaceInstance(DataConnection.class, "mCid", mDefaultDc, DEFAULT_DC_CID);
        doReturn(true).when(mDefaultDc).isActive();
        doReturn(Arrays.asList(mApnContext)).when(mDefaultDc).getApnContexts();
        mDcc.addActiveDcByCid(mDefaultDc);
        assertTrue(mDefaultDc.getApnContexts().stream()
                .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT));
    }

    @Test
    @SmallTest
    public void testDisconnectEvent() throws Exception {
        testConnectEvent();

        mDc.setPduSessionId(5);
        mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
        waitForMs(100);
        disconnectEvent();

        verify(mSimulatedCommandsVerifier, times(1)).unregisterForLceInfo(any(Handler.class));
        verify(mSimulatedCommandsVerifier, times(1))
@@ -618,12 +700,9 @@ public class DataConnectionTest extends TelephonyTest {
                CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
                new String[] {"supl"});

        mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
        waitForMs(100);
        disconnectEvent();
        doReturn(mApn1).when(mApnContext).getApnSetting();
        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mApnContext).getApnTypeBitmask();
        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
        waitForMs(200);
        connectEvent(true);

        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
@@ -631,6 +710,42 @@ public class DataConnectionTest extends TelephonyTest {
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL));
        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
    }

    @Test
    @SmallTest
    public void testEnterpriseNetworkCapability() throws Exception {
        mContextFixture.getCarrierConfigBundle().putStringArray(
                CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                new String[] { "default" });
        doReturn(mApn2).when(mApnContext).getApnSetting();
        testConnectEvent();

        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS));
        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));

        disconnectEvent();
        setUpDefaultData();
        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
        doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting();
        doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType();
        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask();
        connectEvent(true);

        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL));
        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
    }
@@ -740,16 +855,19 @@ public class DataConnectionTest extends TelephonyTest {
        method.setAccessible(true);

        doReturn(apn).when(mApnContext).getApnSetting();
        connectEvent();
        doReturn(apn.getApnTypeBitmask()).when(mApnContext).getApnTypeBitmask();
        connectEvent(true);
        logd(getNetworkCapabilities().toString());

        return (Boolean) method.invoke(mDc);
    }

    private void connectEvent() throws Exception {
    private void connectEvent(boolean validate) {
        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
        waitForMs(200);
        assertEquals("DcActiveState", getCurrentState().getName());
        if (validate) {
            assertTrue(mDc.isActive());
        }
    }

    private void disconnectEvent() throws Exception {
@@ -760,7 +878,7 @@ public class DataConnectionTest extends TelephonyTest {

    @Test
    @SmallTest
    public void testIsIpAddress() throws Exception {
    public void testIsIpAddress() {
        // IPv4
        assertTrue(DataConnection.isIpAddress("1.2.3.4"));
        assertTrue(DataConnection.isIpAddress("127.0.0.1"));
@@ -1066,6 +1184,24 @@ public class DataConnectionTest extends TelephonyTest {
        assertTrue(isUnmeteredUseOnly());
    }

    @Test
    public void testIsEnterpriseUse() throws Exception {
        assertFalse(isEnterpriseUse());
        assertFalse(mDc.getNetworkCapabilities().hasCapability(
                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));

        setUpDefaultData();
        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
        doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting();
        doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType();
        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask();
        connectEvent(true);

        assertTrue(isEnterpriseUse());
        assertTrue(mDc.getNetworkCapabilities().hasCapability(
                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
    }

    @Test
    @SmallTest
    public void testGetDisallowedApnTypes() throws Exception {
+54 −25

File changed.

Preview size limit exceeded, changes collapsed.