From 022081595bf4a082f8354b852eae6d5a015be3fe Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Wed, 3 Nov 2021 18:24:09 +0000 Subject: Tweak volume adjustment rules Test: manual Bug: 197586676 Bug: 202500642 Merged-In: If531a23f5e7b242d3d637966b74b67acfd303199 Change-Id: If531a23f5e7b242d3d637966b74b67acfd303199 --- core/res/res/values/config.xml | 5 +- core/res/res/values/symbols.xml | 2 +- .../volume/VolumeDialogControllerImpl.java | 58 +++++++++++++++++----- .../volume/VolumeDialogControllerImplTest.java | 5 ++ .../android/server/media/MediaSession2Record.java | 6 +++ .../android/server/media/MediaSessionRecord.java | 33 ++++++++++++ .../server/media/MediaSessionRecordImpl.java | 7 +++ .../android/server/media/MediaSessionStack.java | 3 +- 8 files changed, 102 insertions(+), 17 deletions(-) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index acb19eb43a08..68f659633c18 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1894,8 +1894,9 @@ STREAM_MUSIC as if it's on TV platform. --> false - - true + + true diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 66b792c54f80..ccddc0aec925 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4424,7 +4424,7 @@ - + diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index e57059894786..cd6a77836304 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -33,7 +33,11 @@ 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; +import android.media.session.MediaController; import android.media.session.MediaController.PlaybackInfo; import android.media.session.MediaSession.Token; import android.net.Uri; @@ -71,6 +75,7 @@ import com.android.systemui.util.concurrency.ThreadFactory; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -118,6 +123,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private final Context mContext; private final Looper mWorkerLooper; private final PackageManager mPackageManager; + private final MediaRouter2Manager mRouter2Manager; private final WakefulnessLifecycle mWakefulnessLifecycle; private AudioManager mAudio; private IAudioService mAudioService; @@ -179,6 +185,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mWorkerLooper = theadFactory.buildLooperOnNewThread( VolumeDialogControllerImpl.class.getSimpleName()); mWorker = new W(mWorkerLooper); + mRouter2Manager = MediaRouter2Manager.getInstance(mContext); mMediaSessionsCallbacksW = new MediaSessionsCallbacks(mContext); mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW); mAudio = audioManager; @@ -1149,16 +1156,16 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private final HashMap mRemoteStreams = new HashMap<>(); private int mNextStream = DYNAMIC_STREAM_START_INDEX; - private final boolean mShowRemoteSessions; + private final boolean mVolumeAdjustmentForRemoteGroupSessions; public MediaSessionsCallbacks(Context context) { - mShowRemoteSessions = context.getResources().getBoolean( - com.android.internal.R.bool.config_volumeShowRemoteSessions); + mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); } @Override public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) { - if (mShowRemoteSessions) { + if (showForSession(token)) { addStream(token, "onRemoteUpdate"); int stream = 0; @@ -1190,7 +1197,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa @Override public void onRemoteVolumeChanged(Token token, int flags) { - if (mShowRemoteSessions) { + if (showForSession(token)) { addStream(token, "onRemoteVolumeChanged"); int stream = 0; synchronized (mRemoteStreams) { @@ -1214,7 +1221,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa @Override public void onRemoteRemoved(Token token) { - if (mShowRemoteSessions) { + if (showForSession(token)) { int stream = 0; synchronized (mRemoteStreams) { if (!mRemoteStreams.containsKey(token)) { @@ -1233,14 +1240,41 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa } public void setStreamVolume(int stream, int level) { - if (mShowRemoteSessions) { - final Token t = findToken(stream); - if (t == null) { - Log.w(TAG, "setStreamVolume: No token found for stream: " + stream); - return; + final Token token = findToken(stream); + if (token == null) { + Log.w(TAG, "setStreamVolume: No token found for stream: " + stream); + return; + } + if (showForSession(token)) { + mMediaSessions.setVolume(token, level); + } + } + + private boolean showForSession(Token token) { + if (mVolumeAdjustmentForRemoteGroupSessions) { + return true; + } + MediaController ctr = new MediaController(mContext, token); + String packageName = ctr.getPackageName(); + List 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; + } } - mMediaSessions.setVolume(t, level); } + if (!foundNonSystemSession) { + Log.d(TAG, "No routing session for " + packageName); + return false; + } + return !isGroup; } private Token findToken(int stream) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java index 5c0efd36fcd1..c9462d651bc0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java @@ -101,6 +101,11 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase { // Initial non-set value when(mRingerModeLiveData.getValue()).thenReturn(-1); when(mRingerModeInternalLiveData.getValue()).thenReturn(-1); + // Enable group volume adjustments + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions, + true); + mCallback = mock(VolumeDialogControllerImpl.C.class); mThreadFactory.setLooper(TestableLooper.get(this).getLooper()); mVolumeController = new TestableVolumeDialogControllerImpl(mContext, diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java index 607218e20ea8..b424c2083bd4 100644 --- a/services/core/java/com/android/server/media/MediaSession2Record.java +++ b/services/core/java/com/android/server/media/MediaSession2Record.java @@ -145,6 +145,12 @@ public class MediaSession2Record implements MediaSessionRecordImpl { return false; } + @Override + public boolean canHandleVolumeKey() { + // TODO: Implement when MediaSession2 starts to get key events. + return false; + } + @Override public int getSessionPolicies() { synchronized (mLock) { diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 1525cd4da669..e4ed0e5d4186 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -26,7 +26,9 @@ 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; @@ -50,6 +52,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; +import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; @@ -121,6 +124,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR private final SessionCb mSessionCb; private final MediaSessionService mService; private final Context mContext; + private final boolean mVolumeAdjustmentForRemoteGroupSessions; private final Object mLock = new Object(); private final CopyOnWriteArrayList @@ -180,6 +184,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mAudioAttrs = DEFAULT_ATTRIBUTES; mPolicies = policies; + mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); // May throw RemoteException if the session app is killed. mSessionCb.mCb.asBinder().linkToDeath(this, 0); @@ -448,6 +454,33 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR cb); } + @Override + public boolean canHandleVolumeKey() { + if (isPlaybackTypeLocal() || mVolumeAdjustmentForRemoteGroupSessions) { + return true; + } + MediaRouter2Manager mRouter2Manager = MediaRouter2Manager.getInstance(mContext); + List 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 public int getSessionPolicies() { synchronized (mLock) { diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java index 3c50597b8cfc..8f01f02f2ab1 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java @@ -130,6 +130,13 @@ public interface MediaSessionRecordImpl extends AutoCloseable { boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService, KeyEvent ke, int sequenceId, ResultReceiver cb); + /** + * Returns whether the media session can handle volume key events. + * + * @return True if this media session can handle volume key events, false otherwise. + */ + boolean canHandleVolumeKey(); + /** * Get session policies from custom policy provider set when MediaSessionRecord is instantiated. * If custom policy does not exist, will return null. diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index c4c21df746b3..b75ba75e028b 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -325,8 +325,7 @@ class MediaSessionStack { int size = records.size(); for (int i = 0; i < size; i++) { MediaSessionRecord record = records.get(i); - // Do not send the volume key events to remote sessions. - if (record.checkPlaybackActiveState(true) && record.isPlaybackTypeLocal()) { + if (record.checkPlaybackActiveState(true) && record.canHandleVolumeKey()) { mCachedVolumeDefault = record; return record; } -- cgit v1.2.3-59-g8ed1b From b7f52f4468a1daa7408e44fafb362b54eec20897 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Mon, 8 Nov 2021 21:12:36 +0000 Subject: Re-enable volume control for non-grouped devices Bug: 197586676 Bug: 202500642 Test: make -j50 RunSettingsRoboTests Merged-In: I7740d78f3a7dca62d64e6cf7b8c9ffa1578c8e74 Change-Id: I7740d78f3a7dca62d64e6cf7b8c9ffa1578c8e74 --- .../src/com/android/settingslib/media/InfoMediaManager.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 3c43f4a637ba..a383c1e2b680 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -70,6 +70,7 @@ public class InfoMediaManager extends MediaManager { MediaRouter2Manager mRouterManager; @VisibleForTesting String mPackageName; + private final boolean mVolumeAdjustmentForRemoteGroupSessions; private MediaDevice mCurrentConnectedDevice; private LocalBluetoothManager mBluetoothManager; @@ -83,6 +84,9 @@ public class InfoMediaManager extends MediaManager { if (!TextUtils.isEmpty(packageName)) { mPackageName = packageName; } + + mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); } @Override @@ -387,7 +391,9 @@ public class InfoMediaManager extends MediaManager { @TargetApi(Build.VERSION_CODES.R) boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) { - return false; + return sessionInfo.isSystemSession() // System sessions are not remote + || mVolumeAdjustmentForRemoteGroupSessions + || sessionInfo.getSelectedRoutes().size() <= 1; } private void refreshDevices() { -- cgit v1.2.3-59-g8ed1b From 92013ed958dbc7e666ced0c4b0337f03ff9381c8 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Thu, 11 Nov 2021 00:02:44 +0000 Subject: Plumb config to output switcher indication chip Bug: 197586676 Bug: 202500642 Test: manual Merged-In: I71d7f11b9d88dfb9ef74814e9ac7f9d28b0e652c Change-Id: I71d7f11b9d88dfb9ef74814e9ac7f9d28b0e652c --- .../com/android/systemui/media/dialog/MediaOutputController.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index b2def7a8596a..802e5ebaf1c7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -75,6 +75,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { private final ActivityStarter mActivityStarter; private final List mGroupMediaDevices = new CopyOnWriteArrayList<>(); private final boolean mAboveStatusbar; + private final boolean mVolumeAdjustmentForRemoteGroupSessions; private final NotificationEntryManager mNotificationEntryManager; @VisibleForTesting final List mMediaDevices = new CopyOnWriteArrayList<>(); @@ -104,6 +105,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName); mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName); mUiEventLogger = uiEventLogger; + mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); } void start(@NonNull Callback cb) { @@ -466,7 +469,9 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { } boolean isVolumeControlEnabled(@NonNull MediaDevice device) { - return !isActiveRemoteDevice(device); + // TODO(b/202500642): Also enable volume control for remote non-group sessions. + return !isActiveRemoteDevice(device) + || mVolumeAdjustmentForRemoteGroupSessions; } private final MediaController.Callback mCb = new MediaController.Callback() { -- cgit v1.2.3-59-g8ed1b