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

Commit 595b8054 authored by Derek Jedral's avatar Derek Jedral Committed by Android (Google) Code Review
Browse files

Merge "Notify Output Switcher of suggested devices" into main

parents 7e22ad08 fa81fafa
Loading
Loading
Loading
Loading
+167 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
import android.media.SuggestedDeviceInfo;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.os.Build;
@@ -79,6 +80,7 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -124,6 +126,59 @@ public abstract class InfoMediaManager {
         *     android.media.MediaRoute2ProviderService#REASON_INVALID_COMMAND},
         */
        void onRequestFailed(int reason);

        /** Callback for notifying that the suggested device has been updated. */
        default void onSuggestedDeviceUpdated(@Nullable SuggestedDeviceState suggestedDevice) {}
        ;
    }

    /**
     * Wrapper class around SuggestedDeviceInfo and the corresponsing connection state of the
     * suggestion.
     */
    public class SuggestedDeviceState {
        private final SuggestedDeviceInfo mSuggestedDeviceInfo;
        private final @LocalMediaManager.MediaDeviceState int mConnectionState;

        private SuggestedDeviceState(@NonNull SuggestedDeviceInfo suggestedDeviceInfo) {
            mSuggestedDeviceInfo = suggestedDeviceInfo;
            mConnectionState = LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED;
        }

        private SuggestedDeviceState(
                @NonNull SuggestedDeviceInfo suggestedDeviceInfo,
                @LocalMediaManager.MediaDeviceState int state) {
            mSuggestedDeviceInfo = suggestedDeviceInfo;
            mConnectionState = state;
        }

        @NonNull
        public SuggestedDeviceInfo getSuggestedDeviceInfo() {
            return mSuggestedDeviceInfo;
        }

        public @LocalMediaManager.MediaDeviceState int getConnectionState() {
            return mConnectionState;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof SuggestedDeviceState)) {
                return false;
            }
            return Objects.equals(
                            mSuggestedDeviceInfo, ((SuggestedDeviceState) obj).mSuggestedDeviceInfo)
                    && Objects.equals(
                            mConnectionState, ((SuggestedDeviceState) obj).mConnectionState);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mSuggestedDeviceInfo, mConnectionState);
        }
    }

    /** Checked exception that signals the specified package is not present in the system. */
@@ -146,6 +201,9 @@ public abstract class InfoMediaManager {
    private final LocalBluetoothManager mBluetoothManager;
    private final Map<String, RouteListingPreference.Item> mPreferenceItemMap =
            new ConcurrentHashMap<>();
    private final Map<String, List<SuggestedDeviceInfo>> mSuggestedDeviceMap =
            new ConcurrentHashMap<>();
    @Nullable private SuggestedDeviceState mSuggestedDeviceState;

    private final MediaController.Callback mMediaControllerCallback = new MediaControllerCallback();

@@ -629,6 +687,114 @@ public abstract class InfoMediaManager {
                || sessionInfo.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
    }

    protected void updateDeviceSuggestion(
            String suggestingPackageName, @Nullable List<SuggestedDeviceInfo> suggestions) {
        if (suggestions == null) {
            mSuggestedDeviceMap.remove(suggestingPackageName);
        } else {
            mSuggestedDeviceMap.put(suggestingPackageName, suggestions);
        }
        updateDeviceSuggestion();
    }

    protected final void updateDeviceSuggestion() {
        if (!com.android.media.flags.Flags.enableSuggestedDeviceApi()) {
            return;
        }
        SuggestedDeviceInfo topSuggestion = null;
        SuggestedDeviceState newSuggestedDeviceState = null;
        SuggestedDeviceState previousState = mSuggestedDeviceState;
        List<SuggestedDeviceInfo> suggestions = getSuggestions();
        if (suggestions != null && !suggestions.isEmpty()) {
            topSuggestion = suggestions.get(0);
        }
        if (topSuggestion != null) {
            for (MediaDevice device : mMediaDevices) {
                if (Objects.equals(device.getId(), topSuggestion.getRouteId())) {
                    newSuggestedDeviceState =
                            new SuggestedDeviceState(topSuggestion, device.getState());
                    break;
                }
            }
            if (newSuggestedDeviceState == null) {
                newSuggestedDeviceState = new SuggestedDeviceState(topSuggestion);
            }
        }
        if (updateMediaDevicesSuggestionState()) {
            dispatchDeviceListAdded(mMediaDevices);
        }
        if (!Objects.equals(previousState, newSuggestedDeviceState)) {
            mSuggestedDeviceState = newSuggestedDeviceState;
            for (MediaDeviceCallback callback : getCallbacks()) {
                callback.onSuggestedDeviceUpdated(mSuggestedDeviceState);
            }
        }
    }

    @Nullable
    private List<SuggestedDeviceInfo> getSuggestions() {
        // Give suggestions in the following order
        // 1. Suggestions from the local router
        // 2. Suggestions from the proxy router if only one proxy router is providing suggestions
        // 3. No suggestion at all if multiple proxy routers are providing suggestions.
        List<SuggestedDeviceInfo> suggestions = mSuggestedDeviceMap.get(mPackageName);
        if (suggestions != null) {
            return suggestions;
        }
        if (mSuggestedDeviceMap.size() == 1) {
            for (List<SuggestedDeviceInfo> packageSuggestions : mSuggestedDeviceMap.values()) {
                if (packageSuggestions != null) {
                    return packageSuggestions;
                }
            }
        }
        return null;
    }

    // Go through all current MediaDevices, and update the ones that are suggested.
    private boolean updateMediaDevicesSuggestionState() {
        Set<String> suggestedDevices = new HashSet<>();
        // Prioritize suggestions from the package, otherwise pick any.
        List<SuggestedDeviceInfo> suggestions = getSuggestions();
        if (suggestions != null) {
            for (SuggestedDeviceInfo suggestion : suggestions) {
                suggestedDevices.add(suggestion.getRouteId());
            }
        }
        boolean didUpdate = false;
        for (MediaDevice device : mMediaDevices) {
            if (device.isSuggestedDevice()) {
                if (!suggestedDevices.contains(device.getId())) {
                    device.setIsSuggested(false);
                    // Case 1: Device was suggested only by setDeviceSuggestions(), and has been
                    // updated to no longer be suggested.
                    if (!device.isSuggestedByRouteListingPreferences()) {
                        didUpdate = true;
                    }
                    // Case 2: Device was suggested by both setDeviceSuggestions() and RLP. Since
                    // it's still suggested by RLP, no update.
                } else {
                    // Case 3: Device was suggested (either by RLP or by setDeviceSuggestions()),
                    // and should still be suggested.
                    device.setIsSuggested(true);
                }
            } else {
                if (suggestedDevices.contains(device.getId())) {
                    // Case 4: Device was not suggested by either RLP or setDeviceSuggestions() but
                    // is now suggested.
                    device.setIsSuggested(true);
                    didUpdate = true;
                } else {
                    // Case 5: Device was not suggested by either RLP or setDeviceSuggestions() and
                    // is still not suggested.
                    device.setIsSuggested(false);
                }
            }
        }

        return didUpdate;
    }

    protected final synchronized void refreshDevices() {
        rebuildDeviceList();
        dispatchDeviceListAdded(mMediaDevices);
@@ -653,6 +819,7 @@ public abstract class InfoMediaManager {
            // First device on the list is always the first selected route.
            mCurrentConnectedDevice = mMediaDevices.get(0);
        }
        updateDeviceSuggestion();
    }

    private synchronized List<MediaRoute2Info> getAvailableRoutes(
+22 −1
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
    protected final Context mContext;
    protected final MediaRoute2Info mRouteInfo;
    protected final RouteListingPreference.Item mItem;
    private boolean mIsSuggested;

    MediaDevice(
            @NonNull Context context,
@@ -313,11 +314,26 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
    }

    /**
     * Checks if device is suggested device from application
     * Checks if device is suggested device from application. A device can be suggested through
     * either RouteListingPreferences or through MediaRouter2#setDeviceSuggestions.
     *
     * <p>Prioritization and conflict resolution between the two APIs is as follows: - Suggestions
     * from both RLP and the new API will be visible in OSw - Only suggestions from the new API will
     * be visible in both OSw and new UI surfaces such as UMO - If suggestions are provided from
     * local and proxy routers, priority will be given to the local router
     *
     * @return true if device is suggested device
     */
    public boolean isSuggestedDevice() {
        return mIsSuggested || isSuggestedByRouteListingPreferences();
    }

    /**
     * Checks if the device is suggested from the application's RouteListingPreferences
     *
     * @return true if the device is suggested
     */
    public boolean isSuggestedByRouteListingPreferences() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
                && Api34Impl.isSuggestedDevice(mItem);
    }
@@ -434,6 +450,11 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
        return mState;
    }

    /** Sets whether the current device is suggested. */
    public void setIsSuggested(boolean suggested) {
        mIsSuggested = suggested;
    }

    /**
     * Rules:
     * 1. If there is one of the connected devices identified as a carkit or fast pair device,
+31 −0
Original line number Diff line number Diff line
@@ -20,11 +20,13 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2;
import android.media.MediaRouter2.DeviceSuggestionsCallback;
import android.media.MediaRouter2.RoutingController;
import android.media.MediaRouter2Manager;
import android.media.RouteDiscoveryPreference;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
import android.media.SuggestedDeviceInfo;
import android.media.session.MediaController;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -33,6 +35,7 @@ import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.media.flags.Flags;
import com.android.settingslib.bluetooth.LocalBluetoothManager;

@@ -64,6 +67,18 @@ public final class RouterInfoMediaManager extends InfoMediaManager {
                notifyRouteListingPreferenceUpdated(preference);
                refreshDevices();
            };
    private final DeviceSuggestionsCallback mDeviceSuggestionsCallback =
            new DeviceSuggestionsCallback() {
                @Override
                public void onSuggestionUpdated(
                        String suggestingPackageName,
                        List<SuggestedDeviceInfo> suggestedDeviceInfo) {
                    updateDeviceSuggestion(suggestingPackageName, suggestedDeviceInfo);
                }

                @Override
                public void onSuggestionRequested() {} // no-op
            };

    @GuardedBy("this")
    @Nullable
@@ -100,6 +115,20 @@ public final class RouterInfoMediaManager extends InfoMediaManager {
        mRouterManager = MediaRouter2Manager.getInstance(context);
    }

    @VisibleForTesting
    RouterInfoMediaManager(
            Context context,
            @NonNull String packageName,
            @NonNull UserHandle userHandle,
            LocalBluetoothManager localBluetoothManager,
            @Nullable MediaController mediaController,
            MediaRouter2 mediaRouter2,
            MediaRouter2Manager mediaRouter2Manager) {
        super(context, packageName, userHandle, localBluetoothManager, mediaController);
        mRouter = mediaRouter2;
        mRouterManager = mediaRouter2Manager;
    }

    @Override
    protected void startScanOnRouter() {
        if (Flags.enableScreenOffScanning()) {
@@ -120,6 +149,7 @@ public final class RouterInfoMediaManager extends InfoMediaManager {
        mRouter.registerRouteCallback(mExecutor, mRouteCallback, RouteDiscoveryPreference.EMPTY);
        mRouter.registerRouteListingPreferenceUpdatedCallback(
                mExecutor, mRouteListingPreferenceCallback);
        mRouter.registerDeviceSuggestionsCallback(mExecutor, mDeviceSuggestionsCallback);
        mRouter.registerTransferCallback(mExecutor, mTransferCallback);
        mRouter.registerControllerCallback(mExecutor, mControllerCallback);
    }
@@ -143,6 +173,7 @@ public final class RouterInfoMediaManager extends InfoMediaManager {
        mRouter.unregisterControllerCallback(mControllerCallback);
        mRouter.unregisterTransferCallback(mTransferCallback);
        mRouter.unregisterRouteListingPreferenceUpdatedCallback(mRouteListingPreferenceCallback);
        mRouter.unregisterDeviceSuggestionsCallback(mDeviceSuggestionsCallback);
        mRouter.unregisterRouteCallback(mRouteCallback);
    }

+203 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -43,9 +44,13 @@ import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2;
import android.media.MediaRouter2.DeviceSuggestionsCallback;
import android.media.MediaRouter2.RoutingController;
import android.media.MediaRouter2Manager;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
import android.media.SuggestedDeviceInfo;
import android.media.session.MediaSessionManager;
import android.os.Build;
import android.platform.test.annotations.EnableFlags;
@@ -64,6 +69,8 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -141,6 +148,12 @@ public class InfoMediaManagerTest {
    private MediaSessionManager mMediaSessionManager;
    @Mock
    private ComponentName mComponentName;
    @Mock private MediaRouter2 mRouter2;
    @Mock private RoutingController mRoutingController;
    @Captor private ArgumentCaptor<DeviceSuggestionsCallback> mDeviceSuggestionsCallbackCaptor;

    @Captor
    private ArgumentCaptor<InfoMediaManager.SuggestedDeviceState> mSuggestedDeviceStateCaptor;

    private ManagerInfoMediaManager mInfoMediaManager;
    private Context mContext;
@@ -161,6 +174,9 @@ public class InfoMediaManagerTest {
                        /* mediaController */ null);
        mShadowRouter2Manager = ShadowRouter2Manager.getShadow();
        mInfoMediaManager.mRouterManager = MediaRouter2Manager.getInstance(mContext);
        when(mRouter2.getController(any())).thenReturn(mRoutingController);
        when(mRouter2.getControllers()).thenReturn(List.of(mRoutingController));
        when(mRoutingController.getRoutingSessionInfo()).thenReturn(TEST_SYSTEM_ROUTING_SESSION);
    }

    @Test
@@ -445,6 +461,7 @@ public class InfoMediaManagerTest {
        availableRoutes.add(availableInfo4);

        when(mRouterManager.getAvailableRoutes(packageName)).thenReturn(availableRoutes);
        when(mRoutingController.getSelectableRoutes()).thenReturn(availableRoutes);

        return availableRoutes;
    }
@@ -942,6 +959,192 @@ public class InfoMediaManagerTest {
        assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(device);
    }

    private RouterInfoMediaManager createRouterInfoMediaManager() {
        return new RouterInfoMediaManager(
                mContext,
                TEST_PACKAGE_NAME,
                mContext.getUser(),
                mLocalBluetoothManager,
                /* mediaController */ null,
                mRouter2,
                mRouterManager);
    }

    @EnableFlags(Flags.FLAG_ENABLE_SUGGESTED_DEVICE_API)
    @Test
    public void onSuggestionUpdated_listenersNotified() {
        SuggestedDeviceInfo suggestedDeviceInfo =
                new SuggestedDeviceInfo.Builder()
                        .setDeviceDisplayName("device_name")
                        .setRouteId(TEST_ID_3)
                        .setType(0)
                        .build();
        RouterInfoMediaManager mediaManager = createRouterInfoMediaManager();
        setAvailableRoutesList(TEST_PACKAGE_NAME);
        mediaManager.registerCallback(mCallback);
        clearInvocations(mCallback);
        verify(mRouter2)
                .registerDeviceSuggestionsCallback(
                        any(), mDeviceSuggestionsCallbackCaptor.capture());

        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated("random_package_name", List.of(suggestedDeviceInfo));

        verify(mCallback).onDeviceListAdded(any());
        verify(mCallback).onSuggestedDeviceUpdated(mSuggestedDeviceStateCaptor.capture());
        assertThat(mSuggestedDeviceStateCaptor.getValue().getSuggestedDeviceInfo())
                .isEqualTo(suggestedDeviceInfo);
    }

    @EnableFlags(Flags.FLAG_ENABLE_SUGGESTED_DEVICE_API)
    @Test
    public void onSuggestionUpdated_mediaDeviceIsSuggested() {
        SuggestedDeviceInfo suggestedDeviceInfo =
                new SuggestedDeviceInfo.Builder()
                        .setDeviceDisplayName("device_name")
                        .setRouteId(TEST_ID_3)
                        .setType(0)
                        .build();
        RouterInfoMediaManager mediaManager = createRouterInfoMediaManager();
        setAvailableRoutesList(TEST_PACKAGE_NAME);
        mediaManager.registerCallback(mCallback);
        clearInvocations(mCallback);
        verify(mRouter2)
                .registerDeviceSuggestionsCallback(
                        any(), mDeviceSuggestionsCallbackCaptor.capture());

        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated("random_package_name", List.of(suggestedDeviceInfo));

        MediaDevice mediaDevice = mediaManager.mMediaDevices.get(1);
        assertThat(mediaDevice.getId()).isEqualTo(TEST_ID_3);
        assertThat(mediaDevice.isSuggestedDevice()).isTrue();
    }

    @EnableFlags(Flags.FLAG_ENABLE_SUGGESTED_DEVICE_API)
    @Test
    public void onSuggestionUpdated_noSuggestedDevices_noSuggestedMediaDevices() {
        SuggestedDeviceInfo suggestedDeviceInfo =
                new SuggestedDeviceInfo.Builder()
                        .setDeviceDisplayName("device_name")
                        .setRouteId(TEST_ID_3)
                        .setType(0)
                        .build();
        RouterInfoMediaManager mediaManager = createRouterInfoMediaManager();
        setAvailableRoutesList(TEST_PACKAGE_NAME);
        mediaManager.registerCallback(mCallback);
        clearInvocations(mCallback);
        verify(mRouter2)
                .registerDeviceSuggestionsCallback(
                        any(), mDeviceSuggestionsCallbackCaptor.capture());

        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated("random_package_name", List.of(suggestedDeviceInfo));
        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated("random_package_name", null);

        MediaDevice mediaDevice = mediaManager.mMediaDevices.get(1);
        assertThat(mediaDevice.getId()).isEqualTo(TEST_ID_3);
        assertThat(mediaDevice.isSuggestedDevice()).isFalse();
    }

    @EnableFlags(Flags.FLAG_ENABLE_SUGGESTED_DEVICE_API)
    @Test
    public void onSuggestionUpdated_multipleProviders_noSuggestedMediaDevices() {
        SuggestedDeviceInfo suggestedDeviceInfo1 =
                new SuggestedDeviceInfo.Builder()
                        .setDeviceDisplayName("device_name")
                        .setRouteId(TEST_ID_3)
                        .setType(0)
                        .build();
        SuggestedDeviceInfo suggestedDeviceInfo2 =
                new SuggestedDeviceInfo.Builder()
                        .setDeviceDisplayName("device_name_2")
                        .setRouteId(TEST_ID_3)
                        .setType(0)
                        .build();
        RouterInfoMediaManager mediaManager = createRouterInfoMediaManager();
        setAvailableRoutesList(TEST_PACKAGE_NAME);
        mediaManager.registerCallback(mCallback);
        clearInvocations(mCallback);
        verify(mRouter2)
                .registerDeviceSuggestionsCallback(
                        any(), mDeviceSuggestionsCallbackCaptor.capture());

        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated("random_package_name_1", List.of(suggestedDeviceInfo1));
        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated("random_package_name_2", List.of(suggestedDeviceInfo2));

        MediaDevice mediaDevice = mediaManager.mMediaDevices.get(1);
        assertThat(mediaDevice.getId()).isEqualTo(TEST_ID_3);
        assertThat(mediaDevice.isSuggestedDevice()).isFalse();
    }

    @EnableFlags(Flags.FLAG_ENABLE_SUGGESTED_DEVICE_API)
    @Test
    public void onSuggestionUpdated_firstSuggestionFromSamePackage_suggestionIsFromSamePackage() {
        SuggestedDeviceInfo suggestedDeviceInfo =
                new SuggestedDeviceInfo.Builder()
                        .setDeviceDisplayName("device_name")
                        .setRouteId(TEST_ID_3)
                        .setType(0)
                        .build();
        RouterInfoMediaManager mediaManager = createRouterInfoMediaManager();
        setAvailableRoutesList(TEST_PACKAGE_NAME);
        mediaManager.registerCallback(mCallback);
        clearInvocations(mCallback);
        verify(mRouter2)
                .registerDeviceSuggestionsCallback(
                        any(), mDeviceSuggestionsCallbackCaptor.capture());

        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated(TEST_PACKAGE_NAME, List.of(suggestedDeviceInfo));
        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated("random_package_name", null);

        MediaDevice mediaDevice = mediaManager.mMediaDevices.get(1);
        assertThat(mediaDevice.getId()).isEqualTo(TEST_ID_3);
        assertThat(mediaDevice.isSuggestedDevice()).isTrue();
    }

    @EnableFlags(Flags.FLAG_ENABLE_SUGGESTED_DEVICE_API)
    @Test
    public void onSuggestionUpdated_laterSuggestionFromSamePackage_suggestionIsFromSamePackage() {
        SuggestedDeviceInfo suggestedDeviceInfo =
                new SuggestedDeviceInfo.Builder()
                        .setDeviceDisplayName("device_name")
                        .setRouteId(TEST_ID_3)
                        .setType(0)
                        .build();
        RouterInfoMediaManager mediaManager = createRouterInfoMediaManager();
        setAvailableRoutesList(TEST_PACKAGE_NAME);
        mediaManager.registerCallback(mCallback);
        clearInvocations(mCallback);
        verify(mRouter2)
                .registerDeviceSuggestionsCallback(
                        any(), mDeviceSuggestionsCallbackCaptor.capture());

        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated("random_package_name", null);
        mDeviceSuggestionsCallbackCaptor
                .getValue()
                .onSuggestionUpdated(TEST_PACKAGE_NAME, List.of(suggestedDeviceInfo));

        MediaDevice mediaDevice = mediaManager.mMediaDevices.get(1);
        assertThat(mediaDevice.getId()).isEqualTo(TEST_ID_3);
        assertThat(mediaDevice.isSuggestedDevice()).isTrue();
    }

    @EnableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
    @Test
    public void composePreferenceRouteListing_useSystemOrderingIsFalse() {