Get media devices for each media application

Each player, with a separate pacakge name, needs to register a listener
with its own LocalMediaManager object constructed with that package
name.

An issue with this change is that it assumes that the app package for
the player never changes, which is a bad assumption for the mini player.
Luckily, the mini player doesn't show an output switcher, currently.

Fixes: 152469562
Test: manual -- play demo app and switch output to cast device. Verify
that media player shows name of cast device.
Test: manual -- while casting, play music from another app. Verify that
the media player shows phone speaker while the cast app shows cast
device.

Change-Id: Ica508d1b2f1dc51a28027604418c2a4f8d64aa13
This commit is contained in:
Robert Snoeberger
2020-04-09 18:12:27 -04:00
parent bb5e6b49a7
commit 9a7409b68a
4 changed files with 62 additions and 70 deletions

View File

@@ -44,9 +44,11 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.MediaOutputSliceConstants;
import com.android.settingslib.widget.AdaptiveIcon;
@@ -66,6 +68,7 @@ import java.util.concurrent.Executor;
public class MediaControlPanel {
private static final String TAG = "MediaControlPanel";
private final NotificationMediaManager mMediaManager;
@Nullable private final LocalMediaManager mLocalMediaManager;
private final Executor mForegroundExecutor;
private final Executor mBackgroundExecutor;
@@ -77,6 +80,7 @@ public class MediaControlPanel {
private int mForegroundColor;
private int mBackgroundColor;
protected ComponentName mRecvComponent;
private MediaDevice mDevice;
private boolean mIsRegistered = false;
private final int[] mActionIds;
@@ -121,19 +125,44 @@ public class MediaControlPanel {
}
};
private final LocalMediaManager.DeviceCallback mDeviceCallback =
new LocalMediaManager.DeviceCallback() {
@Override
public void onDeviceListUpdate(List<MediaDevice> devices) {
if (mLocalMediaManager == null) {
return;
}
MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
// Check because this can be called several times while changing devices
if (mDevice == null || !mDevice.equals(currentDevice)) {
mDevice = currentDevice;
updateDevice(mDevice);
}
}
@Override
public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
if (mDevice == null || !mDevice.equals(device)) {
mDevice = device;
updateDevice(mDevice);
}
}
};
/**
* Initialize a new control panel
* @param context
* @param parent
* @param manager
* @param routeManager Manager used to listen for device change events.
* @param layoutId layout resource to use for this control panel
* @param actionIds resource IDs for action buttons in the layout
* @param foregroundExecutor foreground executor
* @param backgroundExecutor background executor, used for processing artwork
*/
public MediaControlPanel(Context context, ViewGroup parent, NotificationMediaManager manager,
@LayoutRes int layoutId, int[] actionIds, Executor foregroundExecutor,
Executor backgroundExecutor) {
@Nullable LocalMediaManager routeManager, @LayoutRes int layoutId, int[] actionIds,
Executor foregroundExecutor, Executor backgroundExecutor) {
mContext = context;
LayoutInflater inflater = LayoutInflater.from(mContext);
mMediaNotifView = (LinearLayout) inflater.inflate(layoutId, parent, false);
@@ -144,6 +173,7 @@ public class MediaControlPanel {
// mStateListener to be unregistered in detach.
mMediaNotifView.addOnAttachStateChangeListener(mStateListener);
mMediaManager = manager;
mLocalMediaManager = routeManager;
mActionIds = actionIds;
mForegroundExecutor = foregroundExecutor;
mBackgroundExecutor = backgroundExecutor;
@@ -176,7 +206,7 @@ public class MediaControlPanel {
* @param device
*/
public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor,
int bgColor, PendingIntent contentIntent, String appNameString, MediaDevice device) {
int bgColor, PendingIntent contentIntent, String appNameString) {
mToken = token;
mForegroundColor = iconColor;
mBackgroundColor = bgColor;
@@ -253,9 +283,9 @@ public class MediaControlPanel {
// Transfer chip
mSeamless = mMediaNotifView.findViewById(R.id.media_seamless);
if (mSeamless != null) {
if (mSeamless != null && mLocalMediaManager != null) {
mSeamless.setVisibility(View.VISIBLE);
updateDevice(device);
updateDevice(mLocalMediaManager.getCurrentConnectedDevice());
ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
mSeamless.setOnClickListener(v -> {
final Intent intent = new Intent()
@@ -366,7 +396,7 @@ public class MediaControlPanel {
* Update the current device information
* @param device device information to display
*/
public void updateDevice(MediaDevice device) {
private void updateDevice(MediaDevice device) {
if (mSeamless == null) {
return;
}
@@ -456,6 +486,10 @@ public class MediaControlPanel {
Assert.isMainThread();
if (!mIsRegistered) {
mMediaManager.addCallback(mMediaListener);
if (mLocalMediaManager != null) {
mLocalMediaManager.registerCallback(mDeviceCallback);
mLocalMediaManager.startScan();
}
mIsRegistered = true;
}
}
@@ -463,6 +497,10 @@ public class MediaControlPanel {
private void makeInactive() {
Assert.isMainThread();
if (mIsRegistered) {
if (mLocalMediaManager != null) {
mLocalMediaManager.stopScan();
mLocalMediaManager.unregisterCallback(mDeviceCallback);
}
mMediaManager.removeCallback(mMediaListener);
mIsRegistered = false;
}

View File

@@ -34,7 +34,7 @@ import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.LocalMediaManager;
import com.android.systemui.R;
import com.android.systemui.media.MediaControlPanel;
import com.android.systemui.media.SeekBarObserver;
@@ -74,9 +74,10 @@ public class QSMediaPlayer extends MediaControlPanel {
* @param backgroundExecutor
*/
public QSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager,
Executor foregroundExecutor, DelayableExecutor backgroundExecutor) {
super(context, parent, manager, R.layout.qs_media_panel, QS_ACTION_IDS, foregroundExecutor,
backgroundExecutor);
LocalMediaManager routeManager, Executor foregroundExecutor,
DelayableExecutor backgroundExecutor) {
super(context, parent, manager, routeManager, R.layout.qs_media_panel, QS_ACTION_IDS,
foregroundExecutor, backgroundExecutor);
mParent = (QSPanel) parent;
mBackgroundExecutor = backgroundExecutor;
mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor);
@@ -101,12 +102,12 @@ public class QSMediaPlayer extends MediaControlPanel {
* @param device current playback device
*/
public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor,
int bgColor, View actionsContainer, Notification notif, MediaDevice device) {
int bgColor, View actionsContainer, Notification notif) {
String appName = Notification.Builder.recoverBuilder(getContext(), notif)
.loadHeaderAppName();
super.setMediaSession(token, icon, iconColor, bgColor, notif.contentIntent,
appName, device);
appName);
// Media controls
LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;

View File

@@ -47,7 +47,6 @@ import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.InfoMediaManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
@@ -75,7 +74,6 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
@@ -105,8 +103,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private final LocalBluetoothManager mLocalBluetoothManager;
private final Executor mForegroundExecutor;
private final DelayableExecutor mBackgroundExecutor;
private LocalMediaManager mLocalMediaManager;
private MediaDevice mDevice;
private boolean mUpdateCarousel = false;
protected boolean mExpanded;
@@ -130,34 +126,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private BrightnessMirrorController mBrightnessMirrorController;
private View mDivider;
private final LocalMediaManager.DeviceCallback mDeviceCallback =
new LocalMediaManager.DeviceCallback() {
@Override
public void onDeviceListUpdate(List<MediaDevice> devices) {
if (mLocalMediaManager == null) {
return;
}
MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
// Check because this can be called several times while changing devices
if (mDevice == null || !mDevice.equals(currentDevice)) {
mDevice = currentDevice;
for (QSMediaPlayer p : mMediaPlayers) {
p.updateDevice(mDevice);
}
}
}
@Override
public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
if (mDevice == null || !mDevice.equals(device)) {
mDevice = device;
for (QSMediaPlayer p : mMediaPlayers) {
p.updateDevice(mDevice);
}
}
}
};
@Inject
public QSPanel(
@Named(VIEW_CONTEXT) Context context,
@@ -277,7 +245,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (player == null) {
Log.d(TAG, "creating new player");
player = new QSMediaPlayer(mContext, this, mNotificationMediaManager,
// Set up listener for device changes
// TODO: integrate with MediaTransferManager?
InfoMediaManager imm = new InfoMediaManager(mContext, notif.getPackageName(),
notif.getNotification(), mLocalBluetoothManager);
LocalMediaManager routeManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
imm, notif.getPackageName());
player = new QSMediaPlayer(mContext, this, mNotificationMediaManager, routeManager,
mForegroundExecutor, mBackgroundExecutor);
player.setListening(mListening);
if (player.isPlaying()) {
@@ -292,22 +267,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
Log.d(TAG, "setting player session");
player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
notif.getNotification(), mDevice);
notif.getNotification());
if (mMediaPlayers.size() > 0) {
((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
if (mLocalMediaManager == null) {
// Set up listener for device changes
// TODO: integrate with MediaTransferManager?
InfoMediaManager imm =
new InfoMediaManager(mContext, null, null, mLocalBluetoothManager);
mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm,
null);
mLocalMediaManager.startScan();
mDevice = mLocalMediaManager.getCurrentConnectedDevice();
mLocalMediaManager.registerCallback(mDeviceCallback);
}
}
}
@@ -330,11 +293,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mMediaCarousel.removeView(player.getView());
if (mMediaPlayers.size() == 0) {
((View) mMediaCarousel.getParent()).setVisibility(View.GONE);
if (mLocalMediaManager != null) {
mLocalMediaManager.stopScan();
mLocalMediaManager.unregisterCallback(mDeviceCallback);
mLocalMediaManager = null;
}
}
return true;
}
@@ -404,11 +362,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mBrightnessMirrorController.removeCallback(this);
}
mDumpManager.unregisterDumpable(getDumpableTag());
if (mLocalMediaManager != null) {
mLocalMediaManager.stopScan();
mLocalMediaManager.unregisterCallback(mDeviceCallback);
mLocalMediaManager = null;
}
super.onDetachedFromWindow();
}

View File

@@ -53,7 +53,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel {
*/
public QuickQSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager,
Executor foregroundExecutor, Executor backgroundExecutor) {
super(context, parent, manager, R.layout.qqs_media_panel, QQS_ACTION_IDS,
super(context, parent, manager, null, R.layout.qqs_media_panel, QQS_ACTION_IDS,
foregroundExecutor, backgroundExecutor);
}
@@ -84,7 +84,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel {
return;
}
super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null, null);
super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null);
LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
int i = 0;