mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-11-05 01:26:23 +00:00
Create MediaSessionPlayerUi
This commit is contained in:
parent
ce6f3ca5df
commit
c054ea0737
@ -99,14 +99,13 @@ import org.schabi.newpipe.player.event.PlayerEventListener;
|
||||
import org.schabi.newpipe.player.event.PlayerServiceEventListener;
|
||||
import org.schabi.newpipe.player.helper.AudioReactor;
|
||||
import org.schabi.newpipe.player.helper.LoadController;
|
||||
import org.schabi.newpipe.player.helper.MediaSessionManager;
|
||||
import org.schabi.newpipe.player.helper.PlayerDataSource;
|
||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||
import org.schabi.newpipe.player.mediaitem.MediaItemTag;
|
||||
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
|
||||
import org.schabi.newpipe.player.notification.NotificationPlayerUi;
|
||||
import org.schabi.newpipe.player.playback.MediaSourceManager;
|
||||
import org.schabi.newpipe.player.playback.PlaybackListener;
|
||||
import org.schabi.newpipe.player.playback.PlayerMediaSession;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||
import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
|
||||
@ -196,7 +195,6 @@ public final class Player implements PlaybackListener, Listener {
|
||||
|
||||
private ExoPlayer simpleExoPlayer;
|
||||
private AudioReactor audioReactor;
|
||||
private MediaSessionManager mediaSessionManager;
|
||||
|
||||
@NonNull private final DefaultTrackSelector trackSelector;
|
||||
@NonNull private final LoadController loadController;
|
||||
@ -225,7 +223,7 @@ public final class Player implements PlaybackListener, Listener {
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@SuppressWarnings("MemberName") // keep the unusual member name
|
||||
private final PlayerUiList UIs = new PlayerUiList();
|
||||
private final PlayerUiList UIs;
|
||||
|
||||
private BroadcastReceiver broadcastReceiver;
|
||||
private IntentFilter intentFilter;
|
||||
@ -265,6 +263,15 @@ public final class Player implements PlaybackListener, Listener {
|
||||
|
||||
videoResolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver());
|
||||
audioResolver = new AudioPlaybackResolver(context, dataSource);
|
||||
|
||||
// The UIs added here should always be present. They will be initialized when the player
|
||||
// reaches the initialization step. Make sure the media session ui is before the
|
||||
// notification ui in the UIs list, since the notification depends on the media session in
|
||||
// PlayerUi#initPlayer(), and UIs.call() guarantees UI order is preserved.
|
||||
UIs = new PlayerUiList(
|
||||
new MediaSessionPlayerUi(this),
|
||||
new NotificationPlayerUi(this)
|
||||
);
|
||||
}
|
||||
|
||||
private VideoPlaybackResolver.QualityResolver getQualityResolver() {
|
||||
@ -431,11 +438,6 @@ public final class Player implements PlaybackListener, Listener {
|
||||
}
|
||||
|
||||
private void initUIsForCurrentPlayerType() {
|
||||
//noinspection SimplifyOptionalCallChains
|
||||
if (!UIs.get(NotificationPlayerUi.class).isPresent()) {
|
||||
UIs.addAndPrepare(new NotificationPlayerUi(this));
|
||||
}
|
||||
|
||||
if ((UIs.get(MainPlayerUi.class).isPresent() && playerType == PlayerType.MAIN)
|
||||
|| (UIs.get(PopupPlayerUi.class).isPresent() && playerType == PlayerType.POPUP)) {
|
||||
// correct UI already in place
|
||||
@ -506,8 +508,6 @@ public final class Player implements PlaybackListener, Listener {
|
||||
simpleExoPlayer.setHandleAudioBecomingNoisy(true);
|
||||
|
||||
audioReactor = new AudioReactor(context, simpleExoPlayer);
|
||||
mediaSessionManager = new MediaSessionManager(context, simpleExoPlayer,
|
||||
new PlayerMediaSession(this));
|
||||
|
||||
registerBroadcastReceiver();
|
||||
|
||||
@ -558,9 +558,6 @@ public final class Player implements PlaybackListener, Listener {
|
||||
if (playQueueManager != null) {
|
||||
playQueueManager.dispose();
|
||||
}
|
||||
if (mediaSessionManager != null) {
|
||||
mediaSessionManager.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
@ -723,11 +720,6 @@ public final class Player implements PlaybackListener, Listener {
|
||||
Log.d(TAG, "ACTION_CONFIGURATION_CHANGED received");
|
||||
}
|
||||
break;
|
||||
case Intent.ACTION_HEADSET_PLUG: //FIXME
|
||||
/*notificationManager.cancel(NOTIFICATION_ID);
|
||||
mediaSessionManager.dispose();
|
||||
mediaSessionManager.enable(getBaseContext(), basePlayerImpl.simpleExoPlayer);*/
|
||||
break;
|
||||
}
|
||||
|
||||
UIs.call(playerUi -> playerUi.onBroadcastReceived(intent));
|
||||
@ -1738,15 +1730,6 @@ public final class Player implements PlaybackListener, Listener {
|
||||
initThumbnail(info.getThumbnailUrl());
|
||||
registerStreamViewed();
|
||||
|
||||
final boolean showThumbnail = prefs.getBoolean(
|
||||
context.getString(R.string.show_thumbnail_key), true);
|
||||
mediaSessionManager.setMetadata(
|
||||
getVideoTitle(),
|
||||
getUploaderName(),
|
||||
showThumbnail ? Optional.ofNullable(getThumbnail()) : Optional.empty(),
|
||||
StreamTypeUtil.isLiveStream(info.getStreamType()) ? -1 : info.getDuration()
|
||||
);
|
||||
|
||||
notifyMetadataUpdateToListeners();
|
||||
UIs.call(playerUi -> playerUi.onMetadataChanged(info));
|
||||
}
|
||||
@ -2194,10 +2177,6 @@ public final class Player implements PlaybackListener, Listener {
|
||||
return prefs;
|
||||
}
|
||||
|
||||
public MediaSessionManager getMediaSessionManager() {
|
||||
return mediaSessionManager;
|
||||
}
|
||||
|
||||
|
||||
public PlayerType getPlayerType() {
|
||||
return playerType;
|
||||
|
@ -28,6 +28,7 @@ import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
|
||||
@ -73,9 +74,8 @@ public final class PlayerService extends Service {
|
||||
}
|
||||
|
||||
player.handleIntent(intent);
|
||||
if (player.getMediaSessionManager() != null) {
|
||||
player.getMediaSessionManager().handleMediaButtonIntent(intent);
|
||||
}
|
||||
player.UIs().get(MediaSessionPlayerUi.class)
|
||||
.ifPresent(ui -> ui.handleMediaButtonIntent(intent));
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.schabi.newpipe.player.helper;
|
||||
package org.schabi.newpipe.player.mediasession;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -18,8 +18,6 @@ import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
|
||||
|
||||
import org.schabi.newpipe.MainActivity;
|
||||
import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
|
||||
import org.schabi.newpipe.player.mediasession.PlayQueueNavigator;
|
||||
|
||||
import java.util.Optional;
|
||||
|
@ -0,0 +1,74 @@
|
||||
package org.schabi.newpipe.player.mediasession;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.player.Player;
|
||||
import org.schabi.newpipe.player.playback.PlayerMediaSession;
|
||||
import org.schabi.newpipe.player.ui.PlayerUi;
|
||||
import org.schabi.newpipe.util.StreamTypeUtil;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class MediaSessionPlayerUi extends PlayerUi {
|
||||
|
||||
private MediaSessionManager mediaSessionManager;
|
||||
|
||||
public MediaSessionPlayerUi(@NonNull final Player player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initPlayer() {
|
||||
super.initPlayer();
|
||||
if (mediaSessionManager != null) {
|
||||
mediaSessionManager.dispose();
|
||||
}
|
||||
mediaSessionManager = new MediaSessionManager(context, player.getExoPlayer(),
|
||||
new PlayerMediaSession(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyPlayer() {
|
||||
super.destroyPlayer();
|
||||
if (mediaSessionManager != null) {
|
||||
mediaSessionManager.dispose();
|
||||
mediaSessionManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBroadcastReceived(final Intent intent) {
|
||||
super.onBroadcastReceived(intent);
|
||||
// TODO decide whether to handle ACTION_HEADSET_PLUG or not
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMetadataChanged(@NonNull final StreamInfo info) {
|
||||
super.onMetadataChanged(info);
|
||||
|
||||
final boolean showThumbnail = player.getPrefs().getBoolean(
|
||||
context.getString(R.string.show_thumbnail_key), true);
|
||||
|
||||
mediaSessionManager.setMetadata(
|
||||
player.getVideoTitle(),
|
||||
player.getUploaderName(),
|
||||
showThumbnail ? Optional.ofNullable(player.getThumbnail()) : Optional.empty(),
|
||||
StreamTypeUtil.isLiveStream(info.getStreamType()) ? -1 : info.getDuration()
|
||||
);
|
||||
}
|
||||
|
||||
public void handleMediaButtonIntent(final Intent intent) {
|
||||
if (mediaSessionManager != null) {
|
||||
mediaSessionManager.handleMediaButtonIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<MediaSessionCompat.Token> getSessionToken() {
|
||||
return Optional.ofNullable(mediaSessionManager).map(MediaSessionManager::getSessionToken);
|
||||
}
|
||||
}
|
@ -19,11 +19,13 @@ import androidx.core.content.ContextCompat;
|
||||
import org.schabi.newpipe.MainActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.player.Player;
|
||||
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
||||
import static androidx.media.app.NotificationCompat.MediaStyle;
|
||||
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
|
||||
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
|
||||
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_CLOSE;
|
||||
@ -101,9 +103,11 @@ public final class NotificationUtil {
|
||||
player.getContext(), player.getPrefs(), nonNothingSlotCount);
|
||||
final int[] compactSlots = compactSlotList.stream().mapToInt(Integer::intValue).toArray();
|
||||
|
||||
builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
|
||||
.setMediaSession(player.getMediaSessionManager().getSessionToken())
|
||||
.setShowActionsInCompactView(compactSlots))
|
||||
final MediaStyle mediaStyle = new MediaStyle().setShowActionsInCompactView(compactSlots);
|
||||
player.UIs().get(MediaSessionPlayerUi.class).flatMap(MediaSessionPlayerUi::getSessionToken)
|
||||
.ifPresent(mediaStyle::setMediaSession);
|
||||
|
||||
builder.setStyle(mediaStyle)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setCategory(NotificationCompat.CATEGORY_TRANSPORT)
|
||||
|
@ -29,7 +29,8 @@ public abstract class PlayerUi {
|
||||
@NonNull protected final Player player;
|
||||
|
||||
/**
|
||||
* @param player the player instance that will be usable throughout the lifetime of this UI
|
||||
* @param player the player instance that will be usable throughout the lifetime of this UI; its
|
||||
* context should already have been initialized
|
||||
*/
|
||||
protected PlayerUi(@NonNull final Player player) {
|
||||
this.context = player.getContext();
|
||||
|
@ -8,6 +8,19 @@ import java.util.function.Consumer;
|
||||
public final class PlayerUiList {
|
||||
final List<PlayerUi> playerUis = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a {@link PlayerUiList} starting with the provided player uis. The provided player uis
|
||||
* will not be prepared like those passed to {@link #addAndPrepare(PlayerUi)}, because when
|
||||
* the {@link PlayerUiList} constructor is called, the player is still not running and it
|
||||
* wouldn't make sense to initialize uis then. Instead the player will initialize them by doing
|
||||
* proper calls to {@link #call(Consumer)}.
|
||||
*
|
||||
* @param initialPlayerUis the player uis this list should start with; the order will be kept
|
||||
*/
|
||||
public PlayerUiList(final PlayerUi... initialPlayerUis) {
|
||||
playerUis.addAll(List.of(initialPlayerUis));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the provided player ui to the list and calls on it the initialization functions that
|
||||
* apply based on the current player state. The preparation step needs to be done since when UIs
|
||||
@ -67,11 +80,11 @@ public final class PlayerUiList {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the provided consumer on all player UIs in the list.
|
||||
* Calls the provided consumer on all player UIs in the list, in order of addition.
|
||||
* @param consumer the consumer to call with player UIs
|
||||
*/
|
||||
public void call(final Consumer<PlayerUi> consumer) {
|
||||
//noinspection SimplifyStreamApiCallChains
|
||||
playerUis.stream().forEach(consumer);
|
||||
playerUis.stream().forEachOrdered(consumer);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user