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

Commit b8552342 authored by Iván Budnik's avatar Iván Budnik
Browse files

Fix remote volume adjustment for Android U

Bug: 228021646
Test: Manual
Change-Id: I5d637103fffe2b83fdbae1730a4c9813410185a8
parent c16d400f
Loading
Loading
Loading
Loading
+40 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.media;

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

    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 CharSequence mName;
    final String mOwnerPackageName;
@@ -67,6 +71,7 @@ public final class RoutingSessionInfo implements Parcelable {
    final Bundle mControlHints;
    final boolean mIsSystemSession;


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

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

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

        mControlHints = builder.mControlHints;
        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) {
@@ -115,6 +125,34 @@ public final class RoutingSessionInfo implements Parcelable {
        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) {
        return str != null ? str : "";
    }
+23 −1
Original line number Diff line number Diff line
@@ -19,10 +19,12 @@ package com.android.mediaroutertest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

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

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

import org.junit.Test;
import org.junit.runner.RunWith;
@@ -94,4 +96,24 @@ public class RoutingSessionInfoTest {
        assertEquals(sessionInfoWithProviderId2.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 Diff line number Diff line
@@ -73,7 +73,6 @@ public class InfoMediaManager extends MediaManager {
    MediaRouter2Manager mRouterManager;
    @VisibleForTesting
    String mPackageName;
    private final boolean mVolumeAdjustmentForRemoteGroupSessions;

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

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

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

    boolean isRoutingSessionAvailableForVolumeControl() {
        if (mVolumeAdjustmentForRemoteGroupSessions) {
            return true;
        }
        List<RoutingSessionInfo> sessions =
                mRouterManager.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 (!session.isSystemSession()
                    && session.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED) {
                return true;
            }
        }
        if (!foundNonSystemSession) {

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

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

    private void refreshDevices() {
+8 −14
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IVolumeController;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import android.media.RoutingSessionInfo;
import android.media.VolumePolicy;
@@ -1222,24 +1223,17 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
            String packageName = ctr.getPackageName();
            List<RoutingSessionInfo> sessions =
                    mRouter2Manager.getRoutingSessions(packageName);
            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 (!session.isSystemSession()
                        && session.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED) {
                    return true;
                }
            }
            if (!foundNonSystemSession) {

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

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

    @Override
    public boolean canHandleVolumeKey() {
        if (isPlaybackTypeLocal() || mVolumeAdjustmentForRemoteGroupSessions) {
            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;
        return mVolumeControlType != VolumeProvider.VOLUME_CONTROL_FIXED;
    }

    @Override