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

Commit 96359a4f authored by Jack Yu's avatar Jack Yu
Browse files

Force MMS on IWLAN when needed

Remove MMS capability on cellular network when the
following conditions met,

1. QNS prefers MMS on IWLAN.
2. Carrier has another APN that can support MMS on IWLAN.

This will force MMS to be brought up on IWLAN when MMS
request arrives later.

When the condition is not met, the MMS capability will be
added back to the cellular network.

Fix: 316211526
Test: Basic telephony functionality tests
Test: atest DataNetworkTest
Test: Manually tested MMS with T-Mobile wifi-calling
Change-Id: I85b9dedcea4cb685cb45c98e1ceba52be7811260
parent 51a2da4b
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -104,3 +104,10 @@ flag {
  description: "The DataCallSessionStats metrics will capture whether the IWLAN PDN is set up on cross-SIM calling."
  bug: "313956117"
}

flag {
  name: "force_iwlan_mms"
  namespace: "telephony"
  description: "When QNS prefers MMS on IWLAN, MMS will be attempted on IWLAN if it can, even though if existing cellular network already supports MMS."
  bug: "316211526"
}
+57 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkProvider;
import android.net.NetworkRequest;
import android.net.NetworkScore;
import android.net.ProxyInfo;
import android.net.RouteInfo;
@@ -91,6 +92,7 @@ import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.RIL;
import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback;
import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback;
import com.android.internal.telephony.data.DataEvaluation.DataAllowedReason;
import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList;
@@ -742,6 +744,11 @@ public class DataNetwork extends StateMachine {
     */
    private @Nullable Consumer<Integer> mNetworkValidationResultCodeCallback;

    /**
     * Callback used to listen QNS preference changes.
     */
    private @Nullable AccessNetworksManagerCallback mAccessNetworksManagerCallback;

    /**
     * The network bandwidth.
     */
@@ -1172,6 +1179,23 @@ public class DataNetwork extends StateMachine {
                        getHandler(), EVENT_VOICE_CALL_ENDED, null);
            }

            if (mFlags.forceIwlanMms()) {
                if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_MMS)) {
                    mAccessNetworksManagerCallback = new AccessNetworksManagerCallback(
                            getHandler()::post) {
                        @Override
                        public void onPreferredTransportChanged(
                                @NetCapability int networkCapability) {
                            if (networkCapability == NetworkCapabilities.NET_CAPABILITY_MMS) {
                                log("MMS preference changed.");
                                updateNetworkCapabilities();
                            }
                        }
                    };
                    mAccessNetworksManager.registerCallback(mAccessNetworksManagerCallback);
                }
            }

            // Only add symmetric code here, for example, registering and unregistering.
            // DefaultState.enter() is the starting point in the life cycle of the DataNetwork,
            // and DefaultState.exit() is the end. For non-symmetric initializing works, put them
@@ -1181,6 +1205,10 @@ public class DataNetwork extends StateMachine {
        @Override
        public void exit() {
            logv("Unregistering all events.");
            if (mFlags.forceIwlanMms() && mAccessNetworksManagerCallback != null) {
                mAccessNetworksManager.unregisterCallback(mAccessNetworksManagerCallback);
            }

            // Check null for devices not supporting FEATURE_TELEPHONY_IMS.
            if (mPhone.getImsPhone() != null) {
                mPhone.getImsPhone().getCallTracker().unregisterForVoiceCallStarted(getHandler());
@@ -2333,6 +2361,35 @@ public class DataNetwork extends StateMachine {
            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
        }

        // Check if the feature force MMS on IWLAN is enabled. When the feature is enabled, MMS
        // will be attempted on IWLAN if possible, even if existing cellular networks already
        // supports IWLAN.
        if (mFlags.forceIwlanMms() && builder.build()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
            // If QNS sets MMS preferred on IWLAN, and it is possible to setup an MMS network on
            // IWLAN, then we need to remove the MMS capability on the cellular network. This will
            // allow the new MMS network to be brought up on IWLAN when MMS network request arrives.
            if (mAccessNetworksManager.getPreferredTransportByNetworkCapability(
                    NetworkCapabilities.NET_CAPABILITY_MMS)
                    == AccessNetworkConstants.TRANSPORT_TYPE_WLAN && mTransport
                    == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {

                DataProfile dataProfile = mDataNetworkController.getDataProfileManager()
                        .getDataProfileForNetworkRequest(new TelephonyNetworkRequest(
                                new NetworkRequest.Builder().addCapability(
                                NetworkCapabilities.NET_CAPABILITY_MMS).build(), mPhone),
                        TelephonyManager.NETWORK_TYPE_IWLAN, false, false, false);
                // If we find another data data profile that can support MMS on IWLAN, then remove
                // the MMS capability from this cellular network. This will allow IWLAN to be
                // brought up for MMS later.
                if (dataProfile != null && !dataProfile.equals(mDataProfile)) {
                    log("Found a different data profile " + mDataProfile.getApn()
                            + " that can serve MMS on IWLAN.");
                    builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
                }
            }
        }

        // If one of the capabilities are for special use, for example, IMS, CBS, then this
        // network should be restricted, regardless data is enabled or not.
        if (NetworkCapabilitiesUtils.inferRestrictedCapability(builder.build())
+58 −1
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import android.util.SparseArray;

import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback;
import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback;
import com.android.internal.telephony.data.DataEvaluation.DataAllowedReason;
import com.android.internal.telephony.data.DataNetwork.DataNetworkCallback;
@@ -123,7 +124,7 @@ public class DataNetworkTest extends TelephonyTest {
            .setApnName("fake_apn")
            .setUser("user")
            .setPassword("passwd")
            .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL)
            .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL | ApnSetting.TYPE_MMS)
            .setProtocol(ApnSetting.PROTOCOL_IPV6)
            .setRoamingProtocol(ApnSetting.PROTOCOL_IP)
            .setCarrierEnabled(true)
@@ -134,6 +135,18 @@ public class DataNetworkTest extends TelephonyTest {
            .setMaxConnsTime(789)
            .build();

    private final ApnSetting mMmsApnSetting = new ApnSetting.Builder()
            .setId(2164)
            .setOperatorNumeric("12345")
            .setEntryName("fake_mms_apn")
            .setApnName("fake_mms_apn")
            .setApnTypeBitmask(ApnSetting.TYPE_MMS)
            .setProtocol(ApnSetting.PROTOCOL_IPV6)
            .setRoamingProtocol(ApnSetting.PROTOCOL_IP)
            .setCarrierEnabled(true)
            .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN)
            .build();

    private final ApnSetting mImsApnSetting = new ApnSetting.Builder()
            .setId(2163)
            .setOperatorNumeric("12345")
@@ -157,6 +170,11 @@ public class DataNetworkTest extends TelephonyTest {
            .setTrafficDescriptor(new TrafficDescriptor("fake_apn", null))
            .build();

    private final DataProfile mMmsDataProfile = new DataProfile.Builder()
            .setApnSetting(mMmsApnSetting)
            .setTrafficDescriptor(new TrafficDescriptor("fake_apn", null))
            .build();

    private final DataProfile mImsDataProfile = new DataProfile.Builder()
            .setApnSetting(mImsApnSetting)
            .setTrafficDescriptor(new TrafficDescriptor("fake_apn", null))
@@ -2203,4 +2221,43 @@ public class DataNetworkTest extends TelephonyTest {
                mDataNetworkUT, mDataCallSessionStats);
        processAllMessages();
    }

    @Test
    public void testMmsCapabilityRemovedWhenMmsPreferredOnIwlan() throws Exception {
        doReturn(true).when(mFeatureFlags).forceIwlanMms();
        setupDataNetwork();

        assertThat(mDataNetworkUT.getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)).isTrue();

        ArgumentCaptor<AccessNetworksManagerCallback> accessNetworksManagerCallbackArgumentCaptor =
                ArgumentCaptor.forClass(AccessNetworksManagerCallback.class);
        verify(mAccessNetworksManager).registerCallback(
                accessNetworksManagerCallbackArgumentCaptor.capture());

        // Now QNS prefers MMS on IWLAN
        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
        doReturn(mMmsDataProfile).when(mDataProfileManager).getDataProfileForNetworkRequest(
                any(TelephonyNetworkRequest.class),
                    eq(TelephonyManager.NETWORK_TYPE_IWLAN), eq(false), eq(false), eq(false));
        accessNetworksManagerCallbackArgumentCaptor.getValue()
                .onPreferredTransportChanged(NetworkCapabilities.NET_CAPABILITY_MMS);
        processAllMessages();

        // Check if MMS capability is removed.
        assertThat(mDataNetworkUT.getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)).isFalse();

        // Now QNS prefers MMS on IWLAN
        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
            .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
        accessNetworksManagerCallbackArgumentCaptor.getValue()
                .onPreferredTransportChanged(NetworkCapabilities.NET_CAPABILITY_MMS);
        processAllMessages();

        // Check if MMS capability is added back.
        assertThat(mDataNetworkUT.getNetworkCapabilities()
                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)).isTrue();
    }
}