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

Commit 5681a899 authored by Chung Tang's avatar Chung Tang
Browse files

Refactor mSelectedRoute to List in to support Le Audio sharing in future.

Bug: 385672684
Flag: EXEMPT refactor
Test: atest

Change-Id: I83a54318fcd0f6250d24b9996ea532889a826d88
parent 63edc7c8
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.server.media.BluetoothRouteController.NoOpBluetoothRouteController;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -119,8 +120,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
            new HashMap<>();

    @GuardedBy("this")
    @NonNull
    private MediaRoute2Info mSelectedRoute;
    private List<MediaRoute2Info> mSelectedRoutes = Collections.emptyList();

    // A singleton AudioManagerRouteController.
    private static AudioManagerRouteController mInstance;
@@ -253,8 +253,12 @@ import java.util.concurrent.CopyOnWriteArrayList;

    @Override
    @NonNull
    public synchronized MediaRoute2Info getSelectedRoute() {
        return mSelectedRoute;
    public synchronized List<MediaRoute2Info> getSelectedRoutes() {
        if (mSelectedRoutes.isEmpty()) {
            // mSelectedRoutes should non-empty from initialization.
            throw new IllegalStateException("Selected routes should not be empty");
        }
        return mSelectedRoutes;
    }

    @Override
@@ -474,7 +478,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
        mRouteIdToAvailableDeviceRoutes.put(
                newSelectedRouteHolder.mMediaRoute2Info.getId(),
                selectedRouteHolderWithUpdatedVolumeInfo);
        mSelectedRoute = selectedRouteHolderWithUpdatedVolumeInfo.mMediaRoute2Info;
        mSelectedRoutes =
                Collections.singletonList(
                        selectedRouteHolderWithUpdatedVolumeInfo.mMediaRoute2Info);

        // We only add those BT routes that we have not already obtained from audio manager (which
        // are active).
+4 −4
Original line number Diff line number Diff line
@@ -104,17 +104,17 @@ import java.util.List;
        }
    }

    /** Returns the currently selected device (built-in or wired) route. */
    /** Returns a list of currently selected devices (built-in, wired or bt) route. */
    @NonNull
    MediaRoute2Info getSelectedRoute();
    List<MediaRoute2Info> getSelectedRoutes();

    /**
     * Returns all available routes.
     *
     * <p>Note that this method returns available routes including the selected route because (a)
     * this interface doesn't guarantee that the internal state of the controller won't change
     * between calls to {@link #getSelectedRoute()} and this method and (b) {@link
     * #getSelectedRoute()} may be treated as a transferable route (not a selected route) if the
     * between calls to {@link #getSelectedRoutes()} and this method and (b) {@link
     * #getSelectedRoutes()} may be treated as a transferable route (not a selected route) if the
     * selected route is from {@link BluetoothRouteController}.
     */
    List<MediaRoute2Info> getAvailableRoutes();
+2 −2
Original line number Diff line number Diff line
@@ -129,8 +129,8 @@ import java.util.Objects;

    @Override
    @NonNull
    public synchronized MediaRoute2Info getSelectedRoute() {
        return mDeviceRoute;
    public synchronized List<MediaRoute2Info> getSelectedRoutes() {
        return List.of(mDeviceRoute);
    }

    @Override
+49 −29
Original line number Diff line number Diff line
@@ -42,9 +42,11 @@ import com.android.internal.annotations.GuardedBy;
import com.android.media.flags.Flags;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers.
@@ -69,7 +71,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
    private final DeviceRouteController mDeviceRouteController;
    private final BluetoothRouteController mBluetoothRouteController;

    private String mSelectedRouteId;
    @GuardedBy("mLock")
    private List<String> mSelectedRouteIds = Collections.emptyList();

    /**
     * Placeholder {@link MediaRoute2Info} representation of the currently selected route for apps
@@ -185,19 +188,18 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
            return;
        }

        if (!Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
            if (TextUtils.equals(routeOriginalId, mSelectedRouteId)) {
                RoutingSessionInfo currentSessionInfo;
        synchronized (mLock) {
                    currentSessionInfo =
            if (!Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
                if (mSelectedRouteIds.size() == 1 && mSelectedRouteIds.contains(routeOriginalId)) {
                    RoutingSessionInfo currentSessionInfo =
                            Flags.enableMirroringInMediaRouter2()
                                    ? mSystemSessionInfo
                                    : mSessionInfos.get(0);
                }
                    mCallback.onSessionCreated(this, requestId, currentSessionInfo);
                    return;
                }
            }
        }

        synchronized (mRequestLock) {
            // Handle the previous request as a failure if exists.
@@ -257,7 +259,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
            String sessionOriginalId,
            String routeOriginalId,
            @RoutingSessionInfo.TransferReason int transferReason) {
        String selectedDeviceRouteId = mDeviceRouteController.getSelectedRoute().getId();
        String selectedDeviceRouteId =
                mDeviceRouteController.getSelectedRoutes().getFirst().getId();
        if (TextUtils.equals(routeOriginalId, MediaRoute2Info.ROUTE_ID_DEFAULT)) {
            if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
                // Transfer to the default route (which is the selected route). We replace the id to
@@ -309,9 +312,11 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {

    @Override
    public void setRouteVolume(long requestId, String routeOriginalId, int volume) {
        if (!TextUtils.equals(routeOriginalId, mSelectedRouteId)) {
        synchronized (mLock) {
            if (!mSelectedRouteIds.contains(routeOriginalId)) {
                return;
            }
        }
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
    }

@@ -383,19 +388,27 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
                return null;
            }

            MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute();
            List<MediaRoute2Info> selectedDeviceRoutes = mDeviceRouteController.getSelectedRoutes();

            RoutingSessionInfo.Builder builder =
                    new RoutingSessionInfo.Builder(SYSTEM_SESSION_ID, packageName)
                            .setSystemSession(true);
            builder.addSelectedRoute(selectedDeviceRoute.getId());

            for (MediaRoute2Info route : selectedDeviceRoutes) {
                builder.addSelectedRoute(route.getId());
            }
            for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) {
                builder.addTransferableRoute(route.getId());
            }

            if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
                // Cache to list to avoid redundant list conversions
                Set<String> selectedRouteIds =
                        selectedDeviceRoutes.stream()
                                .map(MediaRoute2Info::getId)
                                .collect(Collectors.toUnmodifiableSet());
                for (MediaRoute2Info route : mDeviceRouteController.getAvailableRoutes()) {
                    if (!TextUtils.equals(selectedDeviceRoute.getId(), route.getId())) {
                    if (!selectedRouteIds.contains(route.getId())) {
                        builder.addTransferableRoute(route.getId());
                    }
                }
@@ -461,7 +474,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
                setProviderState(builder.build());
            }
        } else {
            builder.addRoute(mDeviceRouteController.getSelectedRoute());
            builder.addRoute(mDeviceRouteController.getSelectedRoutes().getFirst());
        }

        for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) {
@@ -490,19 +503,23 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
                    SYSTEM_SESSION_ID, "" /* clientPackageName */)
                    .setSystemSession(true);

            MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute();
            MediaRoute2Info selectedRoute = selectedDeviceRoute;
            List<MediaRoute2Info> selectedDeviceRoutes = mDeviceRouteController.getSelectedRoutes();
            List<MediaRoute2Info> selectedRoutes = selectedDeviceRoutes;
            MediaRoute2Info selectedBtRoute = mBluetoothRouteController.getSelectedRoute();
            List<String> transferableRoutes = new ArrayList<>();

            if (selectedBtRoute != null) {
                selectedRoute = selectedBtRoute;
                selectedRoutes = List.of(selectedBtRoute);
                for (MediaRoute2Info selectedDeviceRoute : selectedDeviceRoutes) {
                    transferableRoutes.add(selectedDeviceRoute.getId());
                }
            mSelectedRouteId = selectedRoute.getId();
            }

            mSelectedRouteIds = selectedRoutes.stream().map(MediaRoute2Info::getId).toList();

            var defaultRouteBuilder =
                    new MediaRoute2Info.Builder(MediaRoute2Info.ROUTE_ID_DEFAULT, selectedRoute)
                    new MediaRoute2Info.Builder(
                                    MediaRoute2Info.ROUTE_ID_DEFAULT, selectedRoutes.getFirst())
                            .setSystemRoute(true)
                            .setProviderId(mUniqueId);
            if (Flags.hideBtAddressFromAppsWithoutBtPermission()) {
@@ -510,11 +527,13 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
            }
            mDefaultRoute = defaultRouteBuilder.build();

            builder.addSelectedRoute(mSelectedRouteId);
            for (String selectedRouteId : mSelectedRouteIds) {
                builder.addSelectedRoute(selectedRouteId);
            }
            if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
                for (MediaRoute2Info route : mDeviceRouteController.getAvailableRoutes()) {
                    String routeId = route.getId();
                    if (!mSelectedRouteId.equals(routeId)) {
                    if (!mSelectedRouteIds.contains(routeId)) {
                        transferableRoutes.add(routeId);
                    }
                }
@@ -533,7 +552,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
                String transferInitiatorPackageName = null;

                if (oldSessionInfo != null
                        && containsSelectedRouteWithId(oldSessionInfo, selectedRoute.getId())) {
                        && containsSelectedRouteWithId(
                                oldSessionInfo, mSelectedRouteIds.getFirst())) {
                    transferReason = oldSessionInfo.getTransferReason();
                    transferInitiatorUserHandle = oldSessionInfo.getTransferInitiatorUserHandle();
                    transferInitiatorPackageName = oldSessionInfo.getTransferInitiatorPackageName();
@@ -542,7 +562,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
                synchronized (mTransferLock) {
                    if (mPendingTransferRequest != null) {
                        boolean isTransferringToTheSelectedRoute =
                                mPendingTransferRequest.isTargetRoute(selectedRoute);
                                mPendingTransferRequest.isTargetRoute(selectedRoutes.getFirst());
                        boolean canBePotentiallyTransferred =
                                mPendingTransferRequest.isTargetRouteIdInRouteOriginalIdList(
                                        transferableRoutes);
@@ -616,8 +636,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
        }

        long pendingRequestId = mPendingSessionCreationOrTransferRequest.mRequestId;
        if (mPendingSessionCreationOrTransferRequest.mTargetOriginalRouteId.equals(
                mSelectedRouteId)) {
        if (mSelectedRouteIds.contains(
                mPendingSessionCreationOrTransferRequest.mTargetOriginalRouteId)) {
            if (DEBUG) {
                Slog.w(
                        TAG,
@@ -705,10 +725,10 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
    @Override
    protected String getDebugString() {
        return TextUtils.formatSimple(
                "%s - package: %s, selected route id: %s, bluetooth impl: %s",
                "%s - package: %s, selected route ids: %s, bluetooth impl: %s",
                getClass().getSimpleName(),
                mComponentName.getPackageName(),
                mSelectedRouteId,
                mSelectedRouteIds,
                mBluetoothRouteController.getClass().getSimpleName());
    }

+11 −11
Original line number Diff line number Diff line
@@ -162,20 +162,20 @@ public class AudioManagerRouteControllerTest {

    @Test
    public void getSelectedRoute_afterDevicesConnect_returnsRightSelectedRoute() {
        assertThat(mControllerUnderTest.getSelectedRoute().getType())
        assertThat(mControllerUnderTest.getSelectedRoutes().getFirst().getType())
                .isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER);

        addAvailableAudioDeviceInfo(
                /* newSelectedDevice= */ FAKE_AUDIO_DEVICE_INFO_BLUETOOTH_A2DP,
                /* newAvailableDevices...= */ FAKE_AUDIO_DEVICE_INFO_BLUETOOTH_A2DP);
        verify(mOnDeviceRouteChangedListener).onDeviceRouteChanged();
        assertThat(mControllerUnderTest.getSelectedRoute().getType())
        assertThat(mControllerUnderTest.getSelectedRoutes().getFirst().getType())
                .isEqualTo(MediaRoute2Info.TYPE_BLUETOOTH_A2DP);

        addAvailableAudioDeviceInfo(
                /* newSelectedDevice= */ null, // Selected device doesn't change.
                /* newAvailableDevices...= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET);
        assertThat(mControllerUnderTest.getSelectedRoute().getType())
        assertThat(mControllerUnderTest.getSelectedRoutes().getFirst().getType())
                .isEqualTo(MediaRoute2Info.TYPE_BLUETOOTH_A2DP);
    }

@@ -191,19 +191,19 @@ public class AudioManagerRouteControllerTest {
                /* newSelectedDevice= */ FAKE_AUDIO_DEVICE_INFO_BLUETOOTH_A2DP,
                /* newAvailableDevices...= */ FAKE_AUDIO_DEVICE_INFO_BLUETOOTH_A2DP);
        verify(mOnDeviceRouteChangedListener, times(2)).onDeviceRouteChanged();
        assertThat(mControllerUnderTest.getSelectedRoute().getType())
        assertThat(mControllerUnderTest.getSelectedRoutes().getFirst().getType())
                .isEqualTo(MediaRoute2Info.TYPE_BLUETOOTH_A2DP);

        removeAvailableAudioDeviceInfos(
                /* newSelectedDevice= */ null,
                /* devicesToRemove...= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET);
        assertThat(mControllerUnderTest.getSelectedRoute().getType())
        assertThat(mControllerUnderTest.getSelectedRoutes().getFirst().getType())
                .isEqualTo(MediaRoute2Info.TYPE_BLUETOOTH_A2DP);

        removeAvailableAudioDeviceInfos(
                /* newSelectedDevice= */ FAKE_AUDIO_DEVICE_INFO_BUILTIN_SPEAKER,
                /* devicesToRemove...= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET);
        assertThat(mControllerUnderTest.getSelectedRoute().getType())
        assertThat(mControllerUnderTest.getSelectedRoutes().getFirst().getType())
                .isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER);
    }

@@ -232,7 +232,7 @@ public class AudioManagerRouteControllerTest {
                                .map(MediaRoute2Info::getType)
                                .toList())
                .containsExactly(MediaRoute2Info.TYPE_BUILTIN_SPEAKER);
        assertThat(mControllerUnderTest.getSelectedRoute().getType())
        assertThat(mControllerUnderTest.getSelectedRoutes().getFirst().getType())
                .isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER);
    }

@@ -269,7 +269,7 @@ public class AudioManagerRouteControllerTest {
                /* newSelectedDevice= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET,
                /* newAvailableDevices...= */ FAKE_AUDIO_DEVICE_INFO_WIRED_HEADSET);

        MediaRoute2Info selectedRoute = mControllerUnderTest.getSelectedRoute();
        MediaRoute2Info selectedRoute = mControllerUnderTest.getSelectedRoutes().getFirst();
        assertThat(selectedRoute.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADSET);
        assertThat(selectedRoute.getVolume()).isEqualTo(2);
        assertThat(selectedRoute.getVolumeMax()).isEqualTo(3);
@@ -292,7 +292,7 @@ public class AudioManagerRouteControllerTest {
        when(mMockAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)).thenReturn(0);
        when(mMockAudioManager.isVolumeFixed()).thenReturn(true);
        mControllerUnderTest.updateVolume(0);
        MediaRoute2Info newSelectedRoute = mControllerUnderTest.getSelectedRoute();
        MediaRoute2Info newSelectedRoute = mControllerUnderTest.getSelectedRoutes().getFirst();
        assertThat(newSelectedRoute.getVolume()).isEqualTo(0);
        assertThat(newSelectedRoute.getVolumeHandling())
                .isEqualTo(MediaRoute2Info.PLAYBACK_VOLUME_FIXED);
@@ -300,14 +300,14 @@ public class AudioManagerRouteControllerTest {

    @Test
    public void getAvailableRoutes_whenNoProductNameIsProvided_usesTypeToPopulateName() {
        assertThat(mControllerUnderTest.getSelectedRoute().getName().toString())
        assertThat(mControllerUnderTest.getSelectedRoutes().getFirst().getName().toString())
                .isEqualTo(FAKE_AUDIO_DEVICE_INFO_BUILTIN_SPEAKER.getProductName().toString());

        addAvailableAudioDeviceInfo(
                /* newSelectedDevice= */ FAKE_AUDIO_DEVICE_NO_NAME,
                /* newAvailableDevices...= */ FAKE_AUDIO_DEVICE_NO_NAME);

        MediaRoute2Info selectedRoute = mControllerUnderTest.getSelectedRoute();
        MediaRoute2Info selectedRoute = mControllerUnderTest.getSelectedRoutes().getFirst();
        assertThat(selectedRoute.getName().toString()).isEqualTo(FAKE_ROUTE_NAME);
    }

Loading