• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

packages/apps/Settings


Commit MetaInfo

Revisión9ed009ad4752b9a416c706578db62850f259be7d (tree)
Tiempo2020-11-24 17:11:56
AutorHugh Chen <hughchen@goog...>
CommiterHugh Chen

Log Message

Fix output switcher will show 2 media session when remote playing

Before this CL, output switcher will show 2 media sessions when
some apps are remote playing. The root cause is some apps will
also create local media sessions when they cast media to remote
playing.

This CL add condition to only show remote sessions on output switcher
if apps both have remote and local sessions.

Bug: 169052790
Test: make -j42 RunSettingsRoboTests
Change-Id: I80479d35b2bb2e353cf41f41f457f2dfd15cadbf
Merged-In: I80479d35b2bb2e353cf41f41f457f2dfd15cadbf
(cherry picked from commit e16a8077b542fdbb54fa30ed18c96948ebb0f42a)

Cambiar Resumen

Diferencia incremental

--- a/src/com/android/settings/media/MediaDeviceUpdateWorker.java
+++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
@@ -30,6 +30,7 @@ import android.net.Uri;
3030 import android.os.UserHandle;
3131 import android.os.UserManager;
3232 import android.text.TextUtils;
33+import android.util.Log;
3334
3435 import androidx.annotation.VisibleForTesting;
3536
@@ -51,6 +52,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
5152 public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
5253 implements LocalMediaManager.DeviceCallback {
5354
55+ private static final String TAG = "MediaDeviceUpdateWorker";
56+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
57+
5458 protected final Context mContext;
5559 protected final Collection<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
5660 private final DevicesChangedBroadcastReceiver mReceiver;
@@ -213,6 +217,10 @@ public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
213217 final List<RoutingSessionInfo> sessionInfos = new ArrayList<>();
214218 for (RoutingSessionInfo info : mLocalMediaManager.getActiveMediaSession()) {
215219 if (!info.isSystemSession()) {
220+ if (DEBUG) {
221+ Log.d(TAG, "getActiveRemoteMediaDevice() info : " + info.toString()
222+ + ", package name : " + info.getClientPackageName());
223+ }
216224 sessionInfos.add(info);
217225 }
218226 }
--- a/src/com/android/settings/media/MediaOutputIndicatorWorker.java
+++ b/src/com/android/settings/media/MediaOutputIndicatorWorker.java
@@ -25,7 +25,6 @@ import android.content.IntentFilter;
2525 import android.media.AudioManager;
2626 import android.media.session.MediaController;
2727 import android.media.session.MediaSessionManager;
28-import android.media.session.PlaybackState;
2928 import android.net.Uri;
3029 import android.text.TextUtils;
3130 import android.util.Log;
@@ -53,6 +52,7 @@ public class MediaOutputIndicatorWorker extends SliceBackgroundWorker implements
5352 LocalMediaManager.DeviceCallback {
5453
5554 private static final String TAG = "MediaOutputIndWorker";
55+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
5656
5757 private final DevicesChangedBroadcastReceiver mReceiver;
5858 private final Context mContext;
@@ -127,24 +127,8 @@ public class MediaOutputIndicatorWorker extends SliceBackgroundWorker implements
127127
128128 @Nullable
129129 MediaController getActiveLocalMediaController() {
130- final MediaSessionManager mMediaSessionManager = mContext.getSystemService(
131- MediaSessionManager.class);
132-
133- for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
134- final MediaController.PlaybackInfo pi = controller.getPlaybackInfo();
135- if (pi == null) {
136- return null;
137- }
138- final PlaybackState playbackState = controller.getPlaybackState();
139- if (playbackState == null) {
140- return null;
141- }
142- if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
143- && playbackState.getState() == PlaybackState.STATE_PLAYING) {
144- return controller;
145- }
146- }
147- return null;
130+ return MediaOutputUtils.getActiveLocalMediaController(mContext.getSystemService(
131+ MediaSessionManager.class));
148132 }
149133
150134 @Override
--- /dev/null
+++ b/src/com/android/settings/media/MediaOutputUtils.java
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright (C) 2020 The Android Open Source Project
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package com.android.settings.media;
17+
18+import android.media.session.MediaController;
19+import android.media.session.MediaSessionManager;
20+import android.media.session.PlaybackState;
21+import android.text.TextUtils;
22+import android.util.Log;
23+
24+import androidx.annotation.Nullable;
25+
26+import com.android.settings.sound.MediaOutputPreferenceController;
27+
28+/**
29+ * Utilities that can be shared between {@link MediaOutputIndicatorWorker} and
30+ * {@link MediaOutputPreferenceController}.
31+ */
32+public class MediaOutputUtils {
33+
34+ private static final String TAG = "MediaOutputUtils";
35+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
36+
37+ /**
38+ * Returns a {@link MediaController} that state is playing and type is local playback,
39+ * and also have active sessions.
40+ */
41+ @Nullable
42+ public static MediaController getActiveLocalMediaController(
43+ MediaSessionManager mediaSessionManager) {
44+
45+ MediaController localController = null;
46+ for (MediaController controller : mediaSessionManager.getActiveSessions(null)) {
47+ final MediaController.PlaybackInfo pi = controller.getPlaybackInfo();
48+ if (pi == null) {
49+ // do nothing
50+ continue;
51+ }
52+ final PlaybackState playbackState = controller.getPlaybackState();
53+ if (playbackState == null) {
54+ // do nothing
55+ continue;
56+ }
57+ if (DEBUG) {
58+ Log.d(TAG, "getActiveLocalMediaController() package name : "
59+ + controller.getPackageName()
60+ + ", play back type : " + pi.getPlaybackType() + ", play back state : "
61+ + playbackState.getState());
62+ }
63+ if (playbackState.getState() != PlaybackState.STATE_PLAYING) {
64+ // do nothing
65+ continue;
66+ }
67+ if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
68+ if (localController != null && TextUtils.equals(localController.getPackageName(),
69+ controller.getPackageName())) {
70+ localController = null;
71+ }
72+ continue;
73+ }
74+ if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
75+ if (localController == null) {
76+ localController = controller;
77+ }
78+ }
79+ }
80+ return localController;
81+ }
82+}
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -22,14 +22,13 @@ import android.content.Intent;
2222 import android.media.AudioManager;
2323 import android.media.session.MediaController;
2424 import android.media.session.MediaSessionManager;
25-import android.media.session.PlaybackState;
2625 import android.text.TextUtils;
2726
28-import androidx.annotation.Nullable;
2927 import androidx.preference.Preference;
3028 import androidx.preference.PreferenceScreen;
3129
3230 import com.android.settings.R;
31+import com.android.settings.media.MediaOutputUtils;
3332 import com.android.settingslib.Utils;
3433 import com.android.settingslib.bluetooth.A2dpProfile;
3534 import com.android.settingslib.bluetooth.HearingAidProfile;
@@ -51,7 +50,8 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
5150
5251 public MediaOutputPreferenceController(Context context, String key) {
5352 super(context, key);
54- mMediaController = getActiveLocalMediaController();
53+ mMediaController = MediaOutputUtils.getActiveLocalMediaController(context.getSystemService(
54+ MediaSessionManager.class));
5555 }
5656
5757 @Override
@@ -141,26 +141,4 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
141141 }
142142 return false;
143143 }
144-
145- @Nullable
146- MediaController getActiveLocalMediaController() {
147- final MediaSessionManager mMediaSessionManager = mContext.getSystemService(
148- MediaSessionManager.class);
149-
150- for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
151- final MediaController.PlaybackInfo pi = controller.getPlaybackInfo();
152- if (pi == null) {
153- return null;
154- }
155- final PlaybackState playbackState = controller.getPlaybackState();
156- if (playbackState == null) {
157- return null;
158- }
159- if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
160- && playbackState.getState() == PlaybackState.STATE_PLAYING) {
161- return controller;
162- }
163- }
164- return null;
165- }
166144 }
--- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java
@@ -261,4 +261,29 @@ public class MediaOutputIndicatorWorkerTest {
261261
262262 assertThat(mMediaOutputIndicatorWorker.getActiveLocalMediaController()).isNull();
263263 }
264+
265+ @Test
266+ public void getActiveLocalMediaController_bothHaveRemoteMediaAndLocalMedia_returnNull() {
267+ final MediaController.PlaybackInfo playbackInfo = new MediaController.PlaybackInfo(
268+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
269+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
270+ 100,
271+ 10,
272+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
273+ null);
274+ final PlaybackState playbackState = new PlaybackState.Builder()
275+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
276+ .build();
277+ final MediaController remoteMediaController = mock(MediaController.class);
278+
279+ mMediaControllers.add(remoteMediaController);
280+ initPlayback();
281+
282+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
283+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
284+ when(remoteMediaController.getPlaybackInfo()).thenReturn(playbackInfo);
285+ when(remoteMediaController.getPlaybackState()).thenReturn(playbackState);
286+
287+ assertThat(mMediaOutputIndicatorWorker.getActiveLocalMediaController()).isNull();
288+ }
264289 }
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputUtilsTest.java
@@ -0,0 +1,153 @@
1+/*
2+ * Copyright (C) 2020 The Android Open Source Project
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+package com.android.settings.media;
17+
18+import static com.google.common.truth.Truth.assertThat;
19+
20+import static org.mockito.ArgumentMatchers.any;
21+import static org.mockito.Mockito.doReturn;
22+import static org.mockito.Mockito.mock;
23+import static org.mockito.Mockito.spy;
24+import static org.mockito.Mockito.when;
25+
26+import android.content.Context;
27+import android.media.AudioAttributes;
28+import android.media.VolumeProvider;
29+import android.media.session.MediaController;
30+import android.media.session.MediaSessionManager;
31+import android.media.session.PlaybackState;
32+
33+import org.junit.Before;
34+import org.junit.Test;
35+import org.junit.runner.RunWith;
36+import org.mockito.Mock;
37+import org.mockito.MockitoAnnotations;
38+import org.robolectric.RobolectricTestRunner;
39+import org.robolectric.RuntimeEnvironment;
40+
41+import java.util.ArrayList;
42+import java.util.List;
43+
44+@RunWith(RobolectricTestRunner.class)
45+public class MediaOutputUtilsTest {
46+
47+ @Mock
48+ private MediaSessionManager mMediaSessionManager;
49+ @Mock
50+ private MediaController mMediaController;
51+
52+ private Context mContext;
53+ private List<MediaController> mMediaControllers = new ArrayList<>();
54+ private PlaybackState mPlaybackState;
55+ private MediaController.PlaybackInfo mPlaybackInfo;
56+
57+ @Before
58+ public void setUp() {
59+ MockitoAnnotations.initMocks(this);
60+
61+ mContext = spy(RuntimeEnvironment.application);
62+ doReturn(mMediaSessionManager).when(mContext).getSystemService(MediaSessionManager.class);
63+ mMediaControllers.add(mMediaController);
64+ doReturn(mMediaControllers).when(mMediaSessionManager).getActiveSessions(any());
65+ }
66+
67+ @Test
68+ public void getActiveLocalMediaController_localMediaPlaying_returnController() {
69+ initPlayback();
70+
71+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
72+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
73+
74+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isEqualTo(
75+ mMediaController);
76+ }
77+
78+ @Test
79+ public void getActiveLocalMediaController_remoteMediaPlaying_returnNull() {
80+ mPlaybackInfo = new MediaController.PlaybackInfo(
81+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
82+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
83+ 100,
84+ 10,
85+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
86+ null);
87+ mPlaybackState = new PlaybackState.Builder()
88+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
89+ .build();
90+
91+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
92+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
93+
94+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isNull();
95+ }
96+
97+ @Test
98+ public void getActiveLocalMediaController_localMediaStopped_returnNull() {
99+ mPlaybackInfo = new MediaController.PlaybackInfo(
100+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
101+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
102+ 100,
103+ 10,
104+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
105+ null);
106+ mPlaybackState = new PlaybackState.Builder()
107+ .setState(PlaybackState.STATE_STOPPED, 0, 1)
108+ .build();
109+
110+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
111+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
112+
113+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isNull();
114+ }
115+
116+ @Test
117+ public void getActiveLocalMediaController_bothHaveRemoteMediaAndLocalMedia_returnNull() {
118+ final MediaController.PlaybackInfo playbackInfo = new MediaController.PlaybackInfo(
119+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
120+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
121+ 100,
122+ 10,
123+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
124+ null);
125+ final PlaybackState playbackState = new PlaybackState.Builder()
126+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
127+ .build();
128+ final MediaController remoteMediaController = mock(MediaController.class);
129+
130+ mMediaControllers.add(remoteMediaController);
131+ initPlayback();
132+
133+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
134+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
135+ when(remoteMediaController.getPlaybackInfo()).thenReturn(playbackInfo);
136+ when(remoteMediaController.getPlaybackState()).thenReturn(playbackState);
137+
138+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isNull();
139+ }
140+
141+ private void initPlayback() {
142+ mPlaybackInfo = new MediaController.PlaybackInfo(
143+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
144+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
145+ 100,
146+ 10,
147+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
148+ null);
149+ mPlaybackState = new PlaybackState.Builder()
150+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
151+ .build();
152+ }
153+}