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

Commit c26fe9bc authored by Iván Budnik's avatar Iván Budnik Committed by Android (Google) Code Review
Browse files

Merge "Fix remote volume adjustment for Android U"

parents d94a307c b8552342
Loading
Loading
Loading
Loading
+40 −2
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package android.media;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
@@ -48,6 +49,9 @@ public final class RoutingSessionInfo implements Parcelable {


    private static final String TAG = "RoutingSessionInfo";
    private static final String TAG = "RoutingSessionInfo";


    private static final String KEY_GROUP_ROUTE = "androidx.mediarouter.media.KEY_GROUP_ROUTE";
    private static final String KEY_VOLUME_HANDLING = "volumeHandling";

    final String mId;
    final String mId;
    final CharSequence mName;
    final CharSequence mName;
    final String mOwnerPackageName;
    final String mOwnerPackageName;
@@ -67,6 +71,7 @@ public final class RoutingSessionInfo implements Parcelable {
    final Bundle mControlHints;
    final Bundle mControlHints;
    final boolean mIsSystemSession;
    final boolean mIsSystemSession;



    RoutingSessionInfo(@NonNull Builder builder) {
    RoutingSessionInfo(@NonNull Builder builder) {
        Objects.requireNonNull(builder, "builder must not be null.");
        Objects.requireNonNull(builder, "builder must not be null.");


@@ -85,12 +90,17 @@ public final class RoutingSessionInfo implements Parcelable {
        mTransferableRoutes = Collections.unmodifiableList(
        mTransferableRoutes = Collections.unmodifiableList(
                convertToUniqueRouteIds(builder.mTransferableRoutes));
                convertToUniqueRouteIds(builder.mTransferableRoutes));


        mVolumeHandling = builder.mVolumeHandling;
        mVolumeMax = builder.mVolumeMax;
        mVolumeMax = builder.mVolumeMax;
        mVolume = builder.mVolume;
        mVolume = builder.mVolume;


        mControlHints = builder.mControlHints;
        mIsSystemSession = builder.mIsSystemSession;
        mIsSystemSession = builder.mIsSystemSession;

        boolean volumeAdjustmentForRemoteGroupSessions = Resources.getSystem().getBoolean(
                com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
        mVolumeHandling = defineVolumeHandling(builder.mVolumeHandling, mSelectedRoutes,
                volumeAdjustmentForRemoteGroupSessions);

        mControlHints = updateVolumeHandlingInHints(builder.mControlHints, mVolumeHandling);
    }
    }


    RoutingSessionInfo(@NonNull Parcel src) {
    RoutingSessionInfo(@NonNull Parcel src) {
@@ -115,6 +125,34 @@ public final class RoutingSessionInfo implements Parcelable {
        mIsSystemSession = src.readBoolean();
        mIsSystemSession = src.readBoolean();
    }
    }


    private static Bundle updateVolumeHandlingInHints(Bundle controlHints, int volumeHandling) {
        // Workaround to preserve retro-compatibility with androidx.
        // See b/228021646 for more details.
        if (controlHints != null && controlHints.containsKey(KEY_GROUP_ROUTE)) {
            Bundle groupRoute = controlHints.getBundle(KEY_GROUP_ROUTE);

            if (groupRoute != null && groupRoute.containsKey(KEY_VOLUME_HANDLING)
                    && volumeHandling != groupRoute.getInt(KEY_VOLUME_HANDLING)) {
                //Creating copy of controlHints with updated value.
                Bundle newGroupRoute = new Bundle(groupRoute);
                newGroupRoute.putInt(KEY_VOLUME_HANDLING, volumeHandling);
                Bundle newControlHints = new Bundle(controlHints);
                newControlHints.putBundle(KEY_GROUP_ROUTE, newGroupRoute);
                return newControlHints;
            }
        }
        //Return same Bundle.
        return controlHints;
    }

    private static int defineVolumeHandling(int volumeHandling, List<String> selectedRoutes,
            boolean volumeAdjustmentForRemoteGroupSessions) {
        if (!volumeAdjustmentForRemoteGroupSessions && selectedRoutes.size() > 1) {
            return MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
        }
        return volumeHandling;
    }

    private static String ensureString(String str) {
    private static String ensureString(String str) {
        return str != null ? str : "";
        return str != null ? str : "";
    }
    }
+23 −1
Original line number Original line Diff line number Diff line
@@ -19,10 +19,12 @@ package com.android.mediaroutertest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotEquals;


import android.content.res.Resources;
import android.media.MediaRoute2Info;
import android.media.RoutingSessionInfo;
import android.media.RoutingSessionInfo;


import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;


import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
@@ -94,4 +96,24 @@ public class RoutingSessionInfoTest {
        assertEquals(sessionInfoWithProviderId2.getTransferableRoutes(),
        assertEquals(sessionInfoWithProviderId2.getTransferableRoutes(),
                sessionInfoWithProviderId.getTransferableRoutes());
                sessionInfoWithProviderId.getTransferableRoutes());
    }
    }

    @Test
    public void testGetVolumeHandlingGroupSession() {
        RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
                TEST_ID, TEST_CLIENT_PACKAGE_NAME)
                .setName(TEST_NAME)
                .addSelectedRoute(TEST_ROUTE_ID_0)
                .addSelectedRoute(TEST_ROUTE_ID_2)
                .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
                .build();

        boolean volumeAdjustmentForRemoteGroupSessions = Resources.getSystem().getBoolean(
                com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);

        int expectedResult = volumeAdjustmentForRemoteGroupSessions
                ? MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE :
                MediaRoute2Info.PLAYBACK_VOLUME_FIXED;

        assertEquals(sessionInfo.getVolumeHandling(), expectedResult);
    }
}
}
+8 −23
Original line number Original line Diff line number Diff line
@@ -73,7 +73,6 @@ public class InfoMediaManager extends MediaManager {
    MediaRouter2Manager mRouterManager;
    MediaRouter2Manager mRouterManager;
    @VisibleForTesting
    @VisibleForTesting
    String mPackageName;
    String mPackageName;
    private final boolean mVolumeAdjustmentForRemoteGroupSessions;


    private MediaDevice mCurrentConnectedDevice;
    private MediaDevice mCurrentConnectedDevice;
    private LocalBluetoothManager mBluetoothManager;
    private LocalBluetoothManager mBluetoothManager;
@@ -87,9 +86,6 @@ public class InfoMediaManager extends MediaManager {
        if (!TextUtils.isEmpty(packageName)) {
        if (!TextUtils.isEmpty(packageName)) {
            mPackageName = packageName;
            mPackageName = packageName;
        }
        }

        mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean(
                com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
    }
    }


    @Override
    @Override
@@ -166,29 +162,19 @@ public class InfoMediaManager extends MediaManager {
    }
    }


    boolean isRoutingSessionAvailableForVolumeControl() {
    boolean isRoutingSessionAvailableForVolumeControl() {
        if (mVolumeAdjustmentForRemoteGroupSessions) {
            return true;
        }
        List<RoutingSessionInfo> sessions =
        List<RoutingSessionInfo> sessions =
                mRouterManager.getRoutingSessions(mPackageName);
                mRouterManager.getRoutingSessions(mPackageName);
        boolean foundNonSystemSession = false;

        boolean isGroup = false;
        for (RoutingSessionInfo session : sessions) {
        for (RoutingSessionInfo session : sessions) {
            if (!session.isSystemSession()) {
            if (!session.isSystemSession()
                foundNonSystemSession = true;
                    && session.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED) {
                int selectedRouteCount = session.getSelectedRoutes().size();
                return true;
                if (selectedRouteCount > 1) {
                    isGroup = true;
                    break;
                }
            }
            }
        }
        }
        if (!foundNonSystemSession) {

        Log.d(TAG, "No routing session for " + mPackageName);
        Log.d(TAG, "No routing session for " + mPackageName);
        return false;
        return false;
    }
    }
        return !isGroup;
    }


    /**
    /**
     * Remove a {@code device} from current media.
     * Remove a {@code device} from current media.
@@ -418,8 +404,7 @@ public class InfoMediaManager extends MediaManager {
    @TargetApi(Build.VERSION_CODES.R)
    @TargetApi(Build.VERSION_CODES.R)
    boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) {
    boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) {
        return sessionInfo.isSystemSession() // System sessions are not remote
        return sessionInfo.isSystemSession() // System sessions are not remote
                || mVolumeAdjustmentForRemoteGroupSessions
                || sessionInfo.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
                || sessionInfo.getSelectedRoutes().size() <= 1;
    }
    }


    private void refreshDevices() {
    private void refreshDevices() {
+8 −14
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@ import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IAudioService;
import android.media.IVolumeController;
import android.media.IVolumeController;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import android.media.MediaRouter2Manager;
import android.media.RoutingSessionInfo;
import android.media.RoutingSessionInfo;
import android.media.VolumePolicy;
import android.media.VolumePolicy;
@@ -1222,24 +1223,17 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
            String packageName = ctr.getPackageName();
            String packageName = ctr.getPackageName();
            List<RoutingSessionInfo> sessions =
            List<RoutingSessionInfo> sessions =
                    mRouter2Manager.getRoutingSessions(packageName);
                    mRouter2Manager.getRoutingSessions(packageName);
            boolean foundNonSystemSession = false;

            boolean isGroup = false;
            for (RoutingSessionInfo session : sessions) {
            for (RoutingSessionInfo session : sessions) {
                if (!session.isSystemSession()) {
                if (!session.isSystemSession()
                    foundNonSystemSession = true;
                        && session.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED) {
                    int selectedRouteCount = session.getSelectedRoutes().size();
                    return true;
                    if (selectedRouteCount > 1) {
                        isGroup = true;
                        break;
                    }
                }
                }
            }
            }
            if (!foundNonSystemSession) {

            Log.d(TAG, "No routing session for " + packageName);
            Log.d(TAG, "No routing session for " + packageName);
            return false;
            return false;
        }
        }
            return !isGroup;
        }


        private Token findToken(int stream) {
        private Token findToken(int stream) {
            synchronized (mRemoteStreams) {
            synchronized (mRemoteStreams) {
+1 −25
Original line number Original line Diff line number Diff line
@@ -26,9 +26,7 @@ import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.AudioSystem;
import android.media.MediaMetadata;
import android.media.MediaMetadata;
import android.media.MediaRouter2Manager;
import android.media.Rating;
import android.media.Rating;
import android.media.RoutingSessionInfo;
import android.media.VolumeProvider;
import android.media.VolumeProvider;
import android.media.session.ISession;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.media.session.ISessionCallback;
@@ -463,29 +461,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR


    @Override
    @Override
    public boolean canHandleVolumeKey() {
    public boolean canHandleVolumeKey() {
        if (isPlaybackTypeLocal() || mVolumeAdjustmentForRemoteGroupSessions) {
        return mVolumeControlType != VolumeProvider.VOLUME_CONTROL_FIXED;
            return true;
        }
        MediaRouter2Manager mRouter2Manager = MediaRouter2Manager.getInstance(mContext);
        List<RoutingSessionInfo> sessions =
                mRouter2Manager.getRoutingSessions(mPackageName);
        boolean foundNonSystemSession = false;
        boolean isGroup = false;
        for (RoutingSessionInfo session : sessions) {
            if (!session.isSystemSession()) {
                foundNonSystemSession = true;
                int selectedRouteCount = session.getSelectedRoutes().size();
                if (selectedRouteCount > 1) {
                    isGroup = true;
                    break;
                }
            }
        }
        if (!foundNonSystemSession) {
            Log.d(TAG, "No routing session for " + mPackageName);
            return false;
        }
        return !isGroup;
    }
    }


    @Override
    @Override