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

Commit 1b1ff48f authored by Chung Tang's avatar Chung Tang Committed by Android (Google) Code Review
Browse files

Merge "Refactor mSelectedRoute to List in to support Le Audio sharing in future." into main

parents 6c6353db 5681a899
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;
@@ -121,8 +122,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;
@@ -255,8 +255,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
@@ -499,7 +503,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
@@ -127,8 +127,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);
    }

@@ -271,7 +271,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);
@@ -294,7 +294,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);
@@ -302,14 +302,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