Loading src/java/com/android/internal/telephony/dataconnection/DataConnection.java +73 −27 Original line number Diff line number Diff line Loading @@ -1354,6 +1354,7 @@ public class DataConnection extends StateMachine { mApnContexts.clear(); mApnSetting = null; mUnmeteredUseOnly = false; mMmsUseOnly = false; mEnterpriseUse = false; mRestrictedNetworkOverride = false; mDcFailCause = DataFailCause.NONE; Loading Loading @@ -1687,6 +1688,14 @@ public class DataConnection extends StateMachine { */ private boolean mUnmeteredUseOnly = false; /** * Indicates if this data connection was established for MMS use only. This is true only when * mobile data is disabled but the user allows sending and receiving MMS messages. If the data * enabled settings indicate that MMS data is allowed unconditionally, MMS can be sent when data * is disabled even if it is a metered APN type. */ private boolean mMmsUseOnly = false; /** * Indicates if when this connection was established we had a restricted/privileged * NetworkRequest and needed it to overcome data-enabled limitations. Loading Loading @@ -1792,6 +1801,18 @@ public class DataConnection extends StateMachine { return true; } /** * @return True if this data connection should only be used for MMS purposes. */ private boolean isMmsUseOnly() { // MMS use only if data is disabled, MMS is allowed unconditionally, and MMS is the only // APN type for this data connection. DataEnabledSettings des = mPhone.getDataEnabledSettings(); boolean mmsAllowedUnconditionally = !des.isDataEnabled() && des.isMmsAlwaysAllowed(); boolean mmsApnOnly = isApnContextAttached(ApnSetting.TYPE_MMS, true); return mmsAllowedUnconditionally && mmsApnOnly; } /** * 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 Loading @@ -1818,22 +1839,21 @@ public class DataConnection extends StateMachine { public NetworkCapabilities getNetworkCapabilities() { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); boolean hasInternet = false; boolean unmeteredApns = false; if (mApnSetting != null && !mEnterpriseUse) { final String[] types = ApnSetting.getApnTypesStringFromBitmask( mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask).split(","); for (String type : types) { if (!mRestrictedNetworkOverride && mUnmeteredUseOnly && ApnSettingUtils.isMeteredApnType( ApnSetting.getApnTypesBitmaskFromString(type), mPhone)) { log("Dropped the metered " + type + " for the unmetered data call."); if (mApnSetting != null && !mEnterpriseUse && !mMmsUseOnly) { final int[] types = ApnSetting.getApnTypesFromBitmask( mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask); for (int type : types) { if ((!mRestrictedNetworkOverride && mUnmeteredUseOnly) && ApnSettingUtils.isMeteredApnType(type, mPhone)) { log("Dropped the metered " + ApnSetting.getApnTypeString(type) + " type for the unmetered data call."); continue; } switch (type) { case ApnSetting.TYPE_ALL_STRING: { hasInternet = true; case ApnSetting.TYPE_ALL: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); Loading @@ -1843,47 +1863,47 @@ public class DataConnection extends StateMachine { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); break; } case ApnSetting.TYPE_DEFAULT_STRING: { hasInternet = true; case ApnSetting.TYPE_DEFAULT: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); break; } case ApnSetting.TYPE_MMS_STRING: { case ApnSetting.TYPE_MMS: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); break; } case ApnSetting.TYPE_SUPL_STRING: { case ApnSetting.TYPE_SUPL: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); break; } case ApnSetting.TYPE_DUN_STRING: { case ApnSetting.TYPE_DUN: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); break; } case ApnSetting.TYPE_FOTA_STRING: { case ApnSetting.TYPE_FOTA: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); break; } case ApnSetting.TYPE_IMS_STRING: { case ApnSetting.TYPE_IMS: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); break; } case ApnSetting.TYPE_CBS_STRING: { case ApnSetting.TYPE_CBS: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); break; } case ApnSetting.TYPE_IA_STRING: { case ApnSetting.TYPE_IA: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); break; } case ApnSetting.TYPE_EMERGENCY_STRING: { case ApnSetting.TYPE_EMERGENCY: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); break; } case ApnSetting.TYPE_MCX_STRING: { case ApnSetting.TYPE_MCX: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX); break; } case ApnSetting.TYPE_XCAP_STRING: { case ApnSetting.TYPE_XCAP: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP); break; } Loading @@ -1891,10 +1911,6 @@ public class DataConnection extends StateMachine { } } if (hasInternet) { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { unmeteredApns = true; } Loading @@ -1917,6 +1933,15 @@ public class DataConnection extends StateMachine { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); } if (mMmsUseOnly) { if (ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)) { log("Adding unmetered capability for the unmetered MMS-only data connection"); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } log("Adding MMS capability for the MMS-only data connection"); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); } if (mRestrictedNetworkOverride) { builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); // don't use dun on restriction-overriden networks. Loading Loading @@ -2825,11 +2850,13 @@ public class DataConnection extends StateMachine { } mUnmeteredUseOnly = isUnmeteredUseOnly(); mMmsUseOnly = isMmsUseOnly(); mEnterpriseUse = isEnterpriseUse(); if (DBG) { log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly + ", mMmsUseOnly = " + mMmsUseOnly + ", mEnterpriseUse = " + mEnterpriseUse); } Loading Loading @@ -3294,6 +3321,8 @@ public class DataConnection extends StateMachine { DataConnection.this); } mMmsUseOnly = isMmsUseOnly(); retVal = HANDLED; break; } Loading Loading @@ -3628,6 +3657,22 @@ public class DataConnection extends StateMachine { return new ArrayList<>(mApnContexts.keySet()); } /** * Return whether there is an ApnContext for the given type in this DataConnection. * @param type APN type to check * @param exclusive true if the given APN type should be the only APN type that exists * @return True if there is an ApnContext for the given type */ private boolean isApnContextAttached(@ApnType int type, boolean exclusive) { boolean attached = mApnContexts.keySet().stream() .map(ApnContext::getApnTypeBitmask) .anyMatch(bitmask -> bitmask == type); if (exclusive) { attached &= mApnContexts.size() == 1; } return attached; } /** Get the network agent of the data connection */ @Nullable DcNetworkAgent getNetworkAgent() { Loading Loading @@ -3952,6 +3997,7 @@ public class DataConnection extends StateMachine { pw.println("mUserData=" + mUserData); pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); pw.println("mMmsUseOnly=" + mMmsUseOnly); pw.println("mEnterpriseUse=" + mEnterpriseUse); pw.println("mUnmeteredOverride=" + mUnmeteredOverride); pw.println("mCongestedOverride=" + mCongestedOverride); Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +71 −0 Original line number Diff line number Diff line Loading @@ -1061,6 +1061,77 @@ public class DcTrackerTest extends TelephonyTest { assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); } @Test @MediumTest public void testTrySetupDataMmsAlwaysAllowedDataDisabled() { mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); mApnSettingContentProvider.setFakeApn1Types("mms,xcap,default"); mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null); sendInitializationEvents(); // Verify MMS was set up and is connected ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class); verify(mSimulatedCommandsVerifier).setupDataCall( eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP | ApnSetting.TYPE_DEFAULT, 1, NETWORK_TYPE_LTE_BITMASK); assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); // Verify DC has all capabilities specified in fakeApn1Types Map<Integer, ApnContext> apnContexts = mDct.getApnContexts().stream().collect( Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET)); // Disable mobile data doReturn(false).when(mDataEnabledSettings).isDataEnabled(); doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); doReturn(false).when(mDataEnabledSettings).isMmsAlwaysAllowed(); mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); // Expected tear down all metered DataConnections waitForMs(200); verify(mSimulatedCommandsVerifier).deactivateDataCall( anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING)); // Allow MMS unconditionally clearInvocations(mSimulatedCommandsVerifier); doReturn(true).when(mDataEnabledSettings).isMmsAlwaysAllowed(); doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS); mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); // Verify MMS was set up and is connected waitForMs(200); verify(mSimulatedCommandsVerifier).setupDataCall( eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); // Ensure MMS data connection has the MMS capability only. apnContexts = mDct.getApnContexts().stream().collect( Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET)); } @Test @MediumTest public void testUserDisableRoaming() { Loading Loading
src/java/com/android/internal/telephony/dataconnection/DataConnection.java +73 −27 Original line number Diff line number Diff line Loading @@ -1354,6 +1354,7 @@ public class DataConnection extends StateMachine { mApnContexts.clear(); mApnSetting = null; mUnmeteredUseOnly = false; mMmsUseOnly = false; mEnterpriseUse = false; mRestrictedNetworkOverride = false; mDcFailCause = DataFailCause.NONE; Loading Loading @@ -1687,6 +1688,14 @@ public class DataConnection extends StateMachine { */ private boolean mUnmeteredUseOnly = false; /** * Indicates if this data connection was established for MMS use only. This is true only when * mobile data is disabled but the user allows sending and receiving MMS messages. If the data * enabled settings indicate that MMS data is allowed unconditionally, MMS can be sent when data * is disabled even if it is a metered APN type. */ private boolean mMmsUseOnly = false; /** * Indicates if when this connection was established we had a restricted/privileged * NetworkRequest and needed it to overcome data-enabled limitations. Loading Loading @@ -1792,6 +1801,18 @@ public class DataConnection extends StateMachine { return true; } /** * @return True if this data connection should only be used for MMS purposes. */ private boolean isMmsUseOnly() { // MMS use only if data is disabled, MMS is allowed unconditionally, and MMS is the only // APN type for this data connection. DataEnabledSettings des = mPhone.getDataEnabledSettings(); boolean mmsAllowedUnconditionally = !des.isDataEnabled() && des.isMmsAlwaysAllowed(); boolean mmsApnOnly = isApnContextAttached(ApnSetting.TYPE_MMS, true); return mmsAllowedUnconditionally && mmsApnOnly; } /** * 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 Loading @@ -1818,22 +1839,21 @@ public class DataConnection extends StateMachine { public NetworkCapabilities getNetworkCapabilities() { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); boolean hasInternet = false; boolean unmeteredApns = false; if (mApnSetting != null && !mEnterpriseUse) { final String[] types = ApnSetting.getApnTypesStringFromBitmask( mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask).split(","); for (String type : types) { if (!mRestrictedNetworkOverride && mUnmeteredUseOnly && ApnSettingUtils.isMeteredApnType( ApnSetting.getApnTypesBitmaskFromString(type), mPhone)) { log("Dropped the metered " + type + " for the unmetered data call."); if (mApnSetting != null && !mEnterpriseUse && !mMmsUseOnly) { final int[] types = ApnSetting.getApnTypesFromBitmask( mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask); for (int type : types) { if ((!mRestrictedNetworkOverride && mUnmeteredUseOnly) && ApnSettingUtils.isMeteredApnType(type, mPhone)) { log("Dropped the metered " + ApnSetting.getApnTypeString(type) + " type for the unmetered data call."); continue; } switch (type) { case ApnSetting.TYPE_ALL_STRING: { hasInternet = true; case ApnSetting.TYPE_ALL: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); Loading @@ -1843,47 +1863,47 @@ public class DataConnection extends StateMachine { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); break; } case ApnSetting.TYPE_DEFAULT_STRING: { hasInternet = true; case ApnSetting.TYPE_DEFAULT: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); break; } case ApnSetting.TYPE_MMS_STRING: { case ApnSetting.TYPE_MMS: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); break; } case ApnSetting.TYPE_SUPL_STRING: { case ApnSetting.TYPE_SUPL: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); break; } case ApnSetting.TYPE_DUN_STRING: { case ApnSetting.TYPE_DUN: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); break; } case ApnSetting.TYPE_FOTA_STRING: { case ApnSetting.TYPE_FOTA: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); break; } case ApnSetting.TYPE_IMS_STRING: { case ApnSetting.TYPE_IMS: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); break; } case ApnSetting.TYPE_CBS_STRING: { case ApnSetting.TYPE_CBS: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); break; } case ApnSetting.TYPE_IA_STRING: { case ApnSetting.TYPE_IA: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); break; } case ApnSetting.TYPE_EMERGENCY_STRING: { case ApnSetting.TYPE_EMERGENCY: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); break; } case ApnSetting.TYPE_MCX_STRING: { case ApnSetting.TYPE_MCX: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX); break; } case ApnSetting.TYPE_XCAP_STRING: { case ApnSetting.TYPE_XCAP: { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP); break; } Loading @@ -1891,10 +1911,6 @@ public class DataConnection extends StateMachine { } } if (hasInternet) { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { unmeteredApns = true; } Loading @@ -1917,6 +1933,15 @@ public class DataConnection extends StateMachine { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); } if (mMmsUseOnly) { if (ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)) { log("Adding unmetered capability for the unmetered MMS-only data connection"); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } log("Adding MMS capability for the MMS-only data connection"); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); } if (mRestrictedNetworkOverride) { builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); // don't use dun on restriction-overriden networks. Loading Loading @@ -2825,11 +2850,13 @@ public class DataConnection extends StateMachine { } mUnmeteredUseOnly = isUnmeteredUseOnly(); mMmsUseOnly = isMmsUseOnly(); mEnterpriseUse = isEnterpriseUse(); if (DBG) { log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly + ", mMmsUseOnly = " + mMmsUseOnly + ", mEnterpriseUse = " + mEnterpriseUse); } Loading Loading @@ -3294,6 +3321,8 @@ public class DataConnection extends StateMachine { DataConnection.this); } mMmsUseOnly = isMmsUseOnly(); retVal = HANDLED; break; } Loading Loading @@ -3628,6 +3657,22 @@ public class DataConnection extends StateMachine { return new ArrayList<>(mApnContexts.keySet()); } /** * Return whether there is an ApnContext for the given type in this DataConnection. * @param type APN type to check * @param exclusive true if the given APN type should be the only APN type that exists * @return True if there is an ApnContext for the given type */ private boolean isApnContextAttached(@ApnType int type, boolean exclusive) { boolean attached = mApnContexts.keySet().stream() .map(ApnContext::getApnTypeBitmask) .anyMatch(bitmask -> bitmask == type); if (exclusive) { attached &= mApnContexts.size() == 1; } return attached; } /** Get the network agent of the data connection */ @Nullable DcNetworkAgent getNetworkAgent() { Loading Loading @@ -3952,6 +3997,7 @@ public class DataConnection extends StateMachine { pw.println("mUserData=" + mUserData); pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); pw.println("mMmsUseOnly=" + mMmsUseOnly); pw.println("mEnterpriseUse=" + mEnterpriseUse); pw.println("mUnmeteredOverride=" + mUnmeteredOverride); pw.println("mCongestedOverride=" + mCongestedOverride); Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +71 −0 Original line number Diff line number Diff line Loading @@ -1061,6 +1061,77 @@ public class DcTrackerTest extends TelephonyTest { assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); } @Test @MediumTest public void testTrySetupDataMmsAlwaysAllowedDataDisabled() { mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); mApnSettingContentProvider.setFakeApn1Types("mms,xcap,default"); mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null); sendInitializationEvents(); // Verify MMS was set up and is connected ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class); verify(mSimulatedCommandsVerifier).setupDataCall( eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP | ApnSetting.TYPE_DEFAULT, 1, NETWORK_TYPE_LTE_BITMASK); assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); // Verify DC has all capabilities specified in fakeApn1Types Map<Integer, ApnContext> apnContexts = mDct.getApnContexts().stream().collect( Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET)); // Disable mobile data doReturn(false).when(mDataEnabledSettings).isDataEnabled(); doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); doReturn(false).when(mDataEnabledSettings).isMmsAlwaysAllowed(); mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); // Expected tear down all metered DataConnections waitForMs(200); verify(mSimulatedCommandsVerifier).deactivateDataCall( anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING)); // Allow MMS unconditionally clearInvocations(mSimulatedCommandsVerifier); doReturn(true).when(mDataEnabledSettings).isMmsAlwaysAllowed(); doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS); mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); // Verify MMS was set up and is connected waitForMs(200); verify(mSimulatedCommandsVerifier).setupDataCall( eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); // Ensure MMS data connection has the MMS capability only. apnContexts = mDct.getApnContexts().stream().collect( Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() .getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET)); } @Test @MediumTest public void testUserDisableRoaming() { Loading