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

Commit ac69f08b authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes If2f73495,I112651ce,Ia3a94642,I35fa1c76,Id2c5b20d, ...

* changes:
  Add enterprise id while registering network factory
  Dynamically changing MMTEL capability
  Don't report data stall for disconnected DataNetwork
  DataRetryManager don't remove unthrottled entries on cleanup
  Fixed the broken tests
  Added NOT_METERED to mutable capabilities
  Fixed IMS handover behavior on roaming network
parents 326ef638 d85df865
Loading
Loading
Loading
Loading
+104 −47
Original line number Diff line number Diff line
@@ -77,7 +77,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseIntArray;

@@ -219,6 +218,15 @@ public class DataNetwork extends StateMachine {
     */
    private static final int EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET = 21;

    /** Event for call started. */
    private static final int EVENT_VOICE_CALL_STARTED = 22;

    /** Event for call ended. */
    private static final int EVENT_VOICE_CALL_ENDED = 23;

    /** Event for CSS indicator changed. */
    private static final int EVENT_CSS_INDICATOR_CHANGED = 24;

    /** The default MTU for IPv4 network. */
    private static final int DEFAULT_MTU_V4 = 1280;

@@ -398,7 +406,15 @@ public class DataNetwork extends StateMachine {
            NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY,
            NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED,
            NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED,
            NetworkCapabilities.NET_CAPABILITY_HEAD_UNIT);
            NetworkCapabilities.NET_CAPABILITY_HEAD_UNIT,
            // Connectivity service will support NOT_METERED as a mutable and requestable
            // capability.
            NetworkCapabilities.NET_CAPABILITY_NOT_METERED,
            // Even though MMTEL is an immutable capability, we still make it an mutable capability
            // here before we have a better solution to deal with network transition from VoPS
            // to non-VoPS network.
            NetworkCapabilities.NET_CAPABILITY_MMTEL
    );

    /** The parent state. Any messages not handled by the child state fallback to this. */
    private final DefaultState mDefaultState = new DefaultState();
@@ -958,15 +974,29 @@ public class DataNetwork extends StateMachine {
            mDataConfigManager.registerForConfigUpdate(getHandler(), EVENT_DATA_CONFIG_UPDATED);
            mPhone.getDisplayInfoController().registerForTelephonyDisplayInfoChanged(
                    getHandler(), EVENT_DISPLAY_INFO_CHANGED, null);
            mPhone.getServiceStateTracker().registerForServiceStateChanged(getHandler(),
                    EVENT_SERVICE_STATE_CHANGED);
            for (int transport : mAccessNetworksManager.getAvailableTransports()) {
                mDataServiceManagers.get(transport)
                        .registerForDataCallListChanged(getHandler(), EVENT_DATA_STATE_CHANGED);
                mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(
                        transport, getHandler(), EVENT_SERVICE_STATE_CHANGED, transport);
            }
            mPhone.getCarrierPrivilegesTracker().registerCarrierPrivilegesListener(getHandler(),
                    EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED, null);

            mPhone.getServiceStateTracker().registerForCssIndicatorChanged(
                    getHandler(), EVENT_CSS_INDICATOR_CHANGED, null);
            mPhone.getCallTracker().registerForVoiceCallStarted(
                    getHandler(), EVENT_VOICE_CALL_STARTED, null);
            mPhone.getCallTracker().registerForVoiceCallEnded(
                    getHandler(), EVENT_VOICE_CALL_ENDED, null);
            // Check null for devices not supporting FEATURE_TELEPHONY_IMS.
            if (mPhone.getImsPhone() != null) {
                mPhone.getImsPhone().getCallTracker().registerForVoiceCallStarted(
                        getHandler(), EVENT_VOICE_CALL_STARTED, null);
                mPhone.getImsPhone().getCallTracker().registerForVoiceCallEnded(
                        getHandler(), EVENT_VOICE_CALL_ENDED, null);
            }

            // 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
@@ -976,13 +1006,21 @@ public class DataNetwork extends StateMachine {
        @Override
        public void exit() {
            logv("Unregistering all events.");
            // Check null for devices not supporting FEATURE_TELEPHONY_IMS.
            if (mPhone.getImsPhone() != null) {
                mPhone.getImsPhone().getCallTracker().unregisterForVoiceCallStarted(getHandler());
                mPhone.getImsPhone().getCallTracker().unregisterForVoiceCallEnded(getHandler());
            }
            mPhone.getCallTracker().unregisterForVoiceCallStarted(getHandler());
            mPhone.getCallTracker().unregisterForVoiceCallEnded(getHandler());

            mPhone.getServiceStateTracker().unregisterForCssIndicatorChanged(getHandler());
            mPhone.getCarrierPrivilegesTracker().unregisterCarrierPrivilegesListener(getHandler());
            for (int transport : mAccessNetworksManager.getAvailableTransports()) {
                mDataServiceManagers.get(transport)
                        .unregisterForDataCallListChanged(getHandler());
                mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(
                        transport, getHandler());
            }
            mPhone.getServiceStateTracker().unregisterForServiceStateChanged(getHandler());
            mPhone.getDisplayInfoController().unregisterForTelephonyDisplayInfoChanged(
                    getHandler());
            mDataConfigManager.unregisterForConfigUpdate(getHandler());
@@ -995,12 +1033,9 @@ public class DataNetwork extends StateMachine {
                    onDataConfigUpdated();
                    break;
                case EVENT_SERVICE_STATE_CHANGED: {
                    // TODO: Should update suspend state when CSS indicator changes.
                    // TODO: Should update suspend state when call started/ended.
                    mDataCallSessionStats.onDrsOrRatChanged(getDataNetworkType());
                    updateSuspendState();
                    updateTcpBufferSizes();
                    updateBandwidthFromDataConfig();
                    updateDataCallSessionStatsOfDrsOrRatChange((AsyncResult) msg.obj);
                    updateNetworkCapabilities();
                    break;
                }
                case EVENT_ATTACH_NETWORK_REQUEST: {
@@ -1042,6 +1077,9 @@ public class DataNetwork extends StateMachine {
                case EVENT_STUCK_IN_TRANSIENT_STATE:
                case EVENT_DISPLAY_INFO_CHANGED:
                case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
                case EVENT_CSS_INDICATOR_CHANGED:
                case EVENT_VOICE_CALL_STARTED:
                case EVENT_VOICE_CALL_ENDED:
                    // Ignore the events when not in the correct state.
                    log("Ignored " + eventToString(msg.what));
                    break;
@@ -1183,10 +1221,6 @@ public class DataNetwork extends StateMachine {
            updateSuspendState();
        }

        @Override
        public void exit() {
        }

        @Override
        public boolean processMessage(Message msg) {
            logv("event=" + eventToString(msg.what));
@@ -1204,7 +1238,7 @@ public class DataNetwork extends StateMachine {
                    // request is from IMS service itself, that means IMS service is already aware
                    // of the tear down. So there is no need to delay in this case.
                    if (tearDownReason != TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED
                            && shouldDelayTearDown()) {
                            && shouldDelayImsTearDown()) {
                        logl("Delay IMS tear down until call ends. reason="
                                + tearDownReasonToString(tearDownReason));
                        break;
@@ -1245,6 +1279,14 @@ public class DataNetwork extends StateMachine {
                    transitionTo(mDisconnectingState);
                    sendMessageDelayed(EVENT_TEAR_DOWN_NETWORK, msg.arg1, msg.arg2);
                    break;
                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;
                default:
                    return NOT_HANDLED;
            }
@@ -1286,6 +1328,9 @@ public class DataNetwork extends StateMachine {
                case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
                case EVENT_DISPLAY_INFO_CHANGED:
                case EVENT_TEAR_DOWN_NETWORK:
                case EVENT_CSS_INDICATOR_CHANGED:
                case EVENT_VOICE_CALL_ENDED:
                case EVENT_VOICE_CALL_STARTED:
                    // Defer the request until handover succeeds or fails.
                    deferMessage(msg);
                    break;
@@ -1410,6 +1455,14 @@ public class DataNetwork extends StateMachine {
                case EVENT_DISPLAY_INFO_CHANGED:
                    onDisplayInfoChanged();
                    break;
                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;
                default:
                    return NOT_HANDLED;
            }
@@ -1675,23 +1728,21 @@ public class DataNetwork extends StateMachine {
                    .forEach(builder::addCapability);
        }

        // If voice call is on-going, do not change MMTEL capability, which is a immutable
        // capability. Changing it will result in re-recreating network agent below, and the voice
        // call will drop. Whether tearing down an IMS network or not when VoPS is lost
        if (mPhone.getImsPhone() != null && mPhone.getImsPhone().getCallTracker().getState()
                != PhoneConstants.State.IDLE && mNetworkCapabilities != null
        // 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
                && 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.
            if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) {
                builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
                if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
                    NetworkRegistrationInfo nri = mPhone.getServiceStateTracker().getServiceState()
                            .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
                                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
                    NetworkRegistrationInfo nri = getNetworkRegistrationInfo();
                    if (nri != null) {
                        DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
                        // Check if VoPS is supported by the network.
@@ -1699,6 +1750,7 @@ public class DataNetwork extends StateMachine {
                                && !dsri.getVopsSupportInfo().isVopsSupported()) {
                            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
                        }
                        log("updateNetworkCapabilities: dsri=" + dsri);
                    }
                }
            }
@@ -1869,6 +1921,8 @@ public class DataNetwork extends StateMachine {
            removeUnsatisfiedNetworkRequests();
            mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback
                    .onNetworkCapabilitiesChanged(DataNetwork.this));
        } else {
            log("updateNetworkCapabilities: Capabilities not changed.");
        }
    }

@@ -1893,19 +1947,6 @@ public class DataNetwork extends StateMachine {
        return mDataProfile;
    }

    /**
     * Once RIL Data Radio Technology changes, the new radio technology will be returned in
     * AsyncResult.
     * See
     * {@link com.android.internal.telephony.ServiceStateTracker#registerForDataRegStateOrRatChanged}
     *
     * @param ar RegistrationInfo: {@code Pair(drs, rat)}
     */
    private void updateDataCallSessionStatsOfDrsOrRatChange(AsyncResult ar) {
        Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>) ar.result;
        mDataCallSessionStats.onDrsOrRatChanged(drsRatPair.second);
    }

    /**
     * Update data suspended state.
     */
@@ -1917,13 +1958,8 @@ public class DataNetwork extends StateMachine {

        boolean newSuspendedState = false;
        // Get the uncombined service state directly.
        NetworkRegistrationInfo nri = mPhone.getServiceStateTracker().getServiceState()
                .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, mTransport);
        if (nri == null) {
            loge("Can't get network registration info for "
                    + AccessNetworkConstants.transportTypeToString(mTransport));
            return;
        }
        NetworkRegistrationInfo nri = getNetworkRegistrationInfo();
        if (nri == null) return;

        // Never set suspended for emergency apn. Emergency data connection
        // can work while device is not in service.
@@ -2290,11 +2326,12 @@ public class DataNetwork extends StateMachine {
    }

    /**
     * @return {@code true} if this tear down should be delayed until call ends on this data
     * network. For now this is specific to IMS network only.
     * @return {@code true} if this is an IMS network and tear down should be delayed until call
     * ends on this data network.
     */
    public boolean shouldDelayTearDown() {
    public boolean shouldDelayImsTearDown() {
        return mDataConfigManager.isImsDelayTearDownEnabled()
                && mNetworkCapabilities != null
                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                && mPhone.getImsPhone() != null
                && mPhone.getImsPhone().getCallTracker().getState()
@@ -2633,6 +2670,20 @@ public class DataNetwork extends StateMachine {
        return new NetworkScore.Builder().setLegacyInt(score).build();
    }

    /**
     * @return Network registration info on the current transport.
     */
    private @Nullable NetworkRegistrationInfo getNetworkRegistrationInfo() {
        NetworkRegistrationInfo nri = mPhone.getServiceStateTracker().getServiceState()
                .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, mTransport);
        if (nri == null) {
            loge("Can't get network registration info for "
                    + AccessNetworkConstants.transportTypeToString(mTransport));
            return null;
        }
        return nri;
    }

    /**
     * Get the APN type network capability. If there are more than one capabilities that are
     * APN-types, then return the highest priority one.
@@ -3052,6 +3103,12 @@ public class DataNetwork extends StateMachine {
                return "EVENT_STUCK_IN_TRANSIENT_STATE";
            case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
                return "EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET";
            case EVENT_VOICE_CALL_STARTED:
                return "EVENT_VOICE_CALL_STARTED";
            case EVENT_VOICE_CALL_ENDED:
                return "EVENT_VOICE_CALL_ENDED";
            case EVENT_CSS_INDICATOR_CHANGED:
                return "EVENT_CSS_INDICATOR_CHANGED";
            default:
                return "Unknown(" + event + ")";
        }
+19 −29
Original line number Diff line number Diff line
@@ -892,7 +892,7 @@ public class DataNetworkController extends Handler {
                                            preferredTransport));
                            return;
                        }
                        if (dataNetwork.shouldDelayTearDown()) {
                        if (dataNetwork.shouldDelayImsTearDown()) {
                            log("onDataNetworkHandoverRetryStopped: Delay IMS tear down until call "
                                    + "ends. " + dataNetwork);
                            return;
@@ -1629,31 +1629,6 @@ public class DataNetworkController extends Handler {
            evaluation.addDataDisallowedReason(DataDisallowedReason.DATA_RESTRICTED_BY_NETWORK);
        }

        boolean delayImsTearDown = false;
        if (dataNetwork.shouldDelayTearDown()) {
            // Some carriers requires delay tearing down IMS network until the call ends even if
            // VoPS bit is lost.
            log("Ignore VoPS bit and delay IMS tear down until call ends.");
            delayImsTearDown = true;
        }

        // Check VoPS support (except for the case that we want to delay IMS tear down until the
        // voice call ends.
        if (!delayImsTearDown
                && dataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
                && dataNetwork.getNetworkCapabilities().hasCapability(
                        NetworkCapabilities.NET_CAPABILITY_MMTEL)) {
            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);
                }
            }
        }

        // Check if device is in CDMA ECBM
        if (mPhone.isInCdmaEcm()) {
            evaluation.addDataDisallowedReason(DataDisallowedReason.CDMA_EMERGENCY_CALLBACK_MODE);
@@ -1831,8 +1806,13 @@ public class DataNetworkController extends Handler {

            // Matching the rules by the configured order. Bail out if find first matching rule.
            for (HandoverRule rule : handoverRules) {
                // Check if the rule is only for roaming and we are not roaming.
                if (rule.isOnlyForRoaming && !mServiceState.getDataRoaming()) continue;
                // Check if the rule is only for roaming and we are not roaming. Use the real
                // roaming state reported by modem instead of using the overridden roaming state.
                if (rule.isOnlyForRoaming && !mServiceState.getDataRoamingFromRegistration()) {
                    // If the rule is for roaming only, and the device is not roaming, then bypass
                    // this rule.
                    continue;
                }

                if (rule.sourceAccessNetworks.contains(sourceAccessNetwork)
                        && rule.targetAccessNetworks.contains(targetAccessNetwork)) {
@@ -2607,8 +2587,18 @@ public class DataNetworkController extends Handler {
            return;
        }

        // TODO: Add DataConfigManager.isRecoveryOnBadNetworkEnabled()
        if (!mDataSettingsManager.isRecoveryOnBadNetworkEnabled()) {
            log("Ignore data network validation status changed becaused"
                    + "data stall recovery is disabled.");
            return;
        }

        if (dataNetwork.isInternetSupported()) {
            if (status == NetworkAgent.VALIDATION_STATUS_NOT_VALID
                    && (dataNetwork.getCurrentState() == null || dataNetwork.isDisconnected())) {
                log("Ignoring invalid validation status for disconnected DataNetwork");
                return;
            }
            mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                    () -> callback.onInternetDataNetworkValidationStatusChanged(status)));
        }
+7 −17
Original line number Diff line number Diff line
@@ -1000,7 +1000,7 @@ public class DataRetryManager extends Handler {
                } else if (ar.result instanceof DataProfile) {
                    dataProfile = (DataProfile) ar.result;
                }
                onDataProfileUnthrottled(dataProfile, apn, transport);
                onDataProfileUnthrottled(dataProfile, apn, transport, true);
                break;
            case EVENT_CANCEL_PENDING_HANDOVER_RETRY:
                onCancelPendingHandoverRetry((DataNetwork) msg.obj);
@@ -1217,24 +1217,11 @@ public class DataRetryManager extends Handler {
                .filter(entry -> entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED)
                .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED));

        final List<ThrottleStatus> throttleStatusList = new ArrayList<>();
        for (DataThrottlingEntry dataThrottlingEntry : mDataThrottlingEntries) {
            DataProfile dataProfile = dataThrottlingEntry.dataProfile;
            String apn = dataProfile.getApnSetting() != null
                    ? dataProfile.getApnSetting().getApnName() : null;
            onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport);
            if (dataProfile.getApnSetting() != null) {
                throttleStatusList.addAll(dataProfile.getApnSetting().getApnTypes()
                        .stream()
                        .map(apnType -> new ThrottleStatus.Builder()
                                .setApnType(apnType)
                                .setSlotIndex(mPhone.getPhoneId())
                                .setNoThrottle()
                                .setRetryType(dataThrottlingEntry.retryType)
                                .setTransportType(dataThrottlingEntry.transport)
                                .build())
                        .collect(Collectors.toList()));
            }
            onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport, false);
        }

        mDataThrottlingEntries.clear();
@@ -1392,9 +1379,10 @@ public class DataRetryManager extends Handler {
     * @param apn The apn to be unthrottled. Note this should be only used for HIDL 1.6 or below.
     * When this is set, {@code dataProfile} must be {@code null}.
     * @param transport The transport that this unthrottling request is on.
     * @param remove Whether to remove unthrottled entries from the list of entries.
     */
    private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn,
            int transport) {
            int transport, boolean remove) {
        long now = SystemClock.elapsedRealtime();
        List<DataThrottlingEntry> dataUnthrottlingEntries = new ArrayList<>();
        if (dataProfile != null) {
@@ -1468,8 +1456,10 @@ public class DataRetryManager extends Handler {
                        .build());
            }
        }
        if (remove) {
            mDataThrottlingEntries.removeAll(dataUnthrottlingEntries);
        }
    }

    /**
     * Check if there is any similar network request scheduled to retry. The definition of similar
+11 −0
Original line number Diff line number Diff line
@@ -564,6 +564,15 @@ public class DataSettingsManager extends Handler {
        return mDataEnabledOverride.isDataAllowedInVoiceCall();
    }

    /**
     * Check whether data stall recovery on bad network is enabled.
     * @return {@code true} if data stall recovery is enabled and {@code false} otherwise.
     */
    public boolean isRecoveryOnBadNetworkEnabled() {
        return Settings.Global.getInt(mResolver,
                Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1) == 1;
    }

    private void notifyDataEnabledChanged(boolean enabled,
            @TelephonyManager.DataEnabledChangedReason int reason) {
        logl("notifyDataEnabledChanged: enabled=" + enabled + ", reason="
@@ -669,6 +678,8 @@ public class DataSettingsManager extends Handler {
        pw.println("device_provisioned=" + Settings.Global.getInt(
                mResolver, Settings.Global.DEVICE_PROVISIONED, 0));
        pw.println("isProvisioningDataEnabled=" + isProvisioningDataEnabled());
        pw.println("data_stall_recovery_on_bad_network=" + Settings.Global.getInt(
                mResolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1));
        pw.println("mDataEnabledSettings=" + mDataEnabledSettings.entrySet().stream()
                .map(entry ->
                        dataEnabledChangedReasonToString(entry.getKey()) + "=" + entry.getValue())
+5 −0
Original line number Diff line number Diff line
@@ -565,6 +565,11 @@ public class PhoneSwitcher extends Handler {
                .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX)
                .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
                .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
                .addEnterpriseId(NetworkCapabilities.NET_ENTERPRISE_ID_1)
                .addEnterpriseId(NetworkCapabilities.NET_ENTERPRISE_ID_2)
                .addEnterpriseId(NetworkCapabilities.NET_ENTERPRISE_ID_3)
                .addEnterpriseId(NetworkCapabilities.NET_ENTERPRISE_ID_4)
                .addEnterpriseId(NetworkCapabilities.NET_ENTERPRISE_ID_5)
                .setNetworkSpecifier(new MatchAllNetworkSpecifier());

        NetworkFactory networkFactory = new PhoneSwitcherNetworkRequestListener(looper, context,
Loading