Skip to content

Commit c054ea0

Browse files
Stypoxlitetex
authored andcommitted
Create MediaSessionPlayerUi
1 parent ce6f3ca commit c054ea0

7 files changed

Lines changed: 113 additions & 44 deletions

File tree

app/src/main/java/org/schabi/newpipe/player/Player.java

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,13 @@
9999
import org.schabi.newpipe.player.event.PlayerServiceEventListener;
100100
import org.schabi.newpipe.player.helper.AudioReactor;
101101
import org.schabi.newpipe.player.helper.LoadController;
102-
import org.schabi.newpipe.player.helper.MediaSessionManager;
103102
import org.schabi.newpipe.player.helper.PlayerDataSource;
104103
import org.schabi.newpipe.player.helper.PlayerHelper;
105104
import org.schabi.newpipe.player.mediaitem.MediaItemTag;
105+
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
106106
import org.schabi.newpipe.player.notification.NotificationPlayerUi;
107107
import org.schabi.newpipe.player.playback.MediaSourceManager;
108108
import org.schabi.newpipe.player.playback.PlaybackListener;
109-
import org.schabi.newpipe.player.playback.PlayerMediaSession;
110109
import org.schabi.newpipe.player.playqueue.PlayQueue;
111110
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
112111
import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
@@ -196,7 +195,6 @@ public final class Player implements PlaybackListener, Listener {
196195

197196
private ExoPlayer simpleExoPlayer;
198197
private AudioReactor audioReactor;
199-
private MediaSessionManager mediaSessionManager;
200198

201199
@NonNull private final DefaultTrackSelector trackSelector;
202200
@NonNull private final LoadController loadController;
@@ -225,7 +223,7 @@ public final class Player implements PlaybackListener, Listener {
225223
//////////////////////////////////////////////////////////////////////////*/
226224

227225
@SuppressWarnings("MemberName") // keep the unusual member name
228-
private final PlayerUiList UIs = new PlayerUiList();
226+
private final PlayerUiList UIs;
229227

230228
private BroadcastReceiver broadcastReceiver;
231229
private IntentFilter intentFilter;
@@ -265,6 +263,15 @@ public Player(@NonNull final PlayerService service) {
265263

266264
videoResolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver());
267265
audioResolver = new AudioPlaybackResolver(context, dataSource);
266+
267+
// The UIs added here should always be present. They will be initialized when the player
268+
// reaches the initialization step. Make sure the media session ui is before the
269+
// notification ui in the UIs list, since the notification depends on the media session in
270+
// PlayerUi#initPlayer(), and UIs.call() guarantees UI order is preserved.
271+
UIs = new PlayerUiList(
272+
new MediaSessionPlayerUi(this),
273+
new NotificationPlayerUi(this)
274+
);
268275
}
269276

270277
private VideoPlaybackResolver.QualityResolver getQualityResolver() {
@@ -431,11 +438,6 @@ && isPlaybackResumeEnabled(this)
431438
}
432439

433440
private void initUIsForCurrentPlayerType() {
434-
//noinspection SimplifyOptionalCallChains
435-
if (!UIs.get(NotificationPlayerUi.class).isPresent()) {
436-
UIs.addAndPrepare(new NotificationPlayerUi(this));
437-
}
438-
439441
if ((UIs.get(MainPlayerUi.class).isPresent() && playerType == PlayerType.MAIN)
440442
|| (UIs.get(PopupPlayerUi.class).isPresent() && playerType == PlayerType.POPUP)) {
441443
// correct UI already in place
@@ -506,8 +508,6 @@ private void initPlayer(final boolean playOnReady) {
506508
simpleExoPlayer.setHandleAudioBecomingNoisy(true);
507509

508510
audioReactor = new AudioReactor(context, simpleExoPlayer);
509-
mediaSessionManager = new MediaSessionManager(context, simpleExoPlayer,
510-
new PlayerMediaSession(this));
511511

512512
registerBroadcastReceiver();
513513

@@ -558,9 +558,6 @@ private void destroyPlayer() {
558558
if (playQueueManager != null) {
559559
playQueueManager.dispose();
560560
}
561-
if (mediaSessionManager != null) {
562-
mediaSessionManager.dispose();
563-
}
564561
}
565562

566563
public void destroy() {
@@ -723,11 +720,6 @@ private void onBroadcastReceived(final Intent intent) {
723720
Log.d(TAG, "ACTION_CONFIGURATION_CHANGED received");
724721
}
725722
break;
726-
case Intent.ACTION_HEADSET_PLUG: //FIXME
727-
/*notificationManager.cancel(NOTIFICATION_ID);
728-
mediaSessionManager.dispose();
729-
mediaSessionManager.enable(getBaseContext(), basePlayerImpl.simpleExoPlayer);*/
730-
break;
731723
}
732724

733725
UIs.call(playerUi -> playerUi.onBroadcastReceived(intent));
@@ -1738,15 +1730,6 @@ private void updateMetadataWith(@NonNull final StreamInfo info) {
17381730
initThumbnail(info.getThumbnailUrl());
17391731
registerStreamViewed();
17401732

1741-
final boolean showThumbnail = prefs.getBoolean(
1742-
context.getString(R.string.show_thumbnail_key), true);
1743-
mediaSessionManager.setMetadata(
1744-
getVideoTitle(),
1745-
getUploaderName(),
1746-
showThumbnail ? Optional.ofNullable(getThumbnail()) : Optional.empty(),
1747-
StreamTypeUtil.isLiveStream(info.getStreamType()) ? -1 : info.getDuration()
1748-
);
1749-
17501733
notifyMetadataUpdateToListeners();
17511734
UIs.call(playerUi -> playerUi.onMetadataChanged(info));
17521735
}
@@ -2194,10 +2177,6 @@ public SharedPreferences getPrefs() {
21942177
return prefs;
21952178
}
21962179

2197-
public MediaSessionManager getMediaSessionManager() {
2198-
return mediaSessionManager;
2199-
}
2200-
22012180

22022181
public PlayerType getPlayerType() {
22032182
return playerType;

app/src/main/java/org/schabi/newpipe/player/PlayerService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import android.os.IBinder;
2929
import android.util.Log;
3030

31+
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
3132
import org.schabi.newpipe.util.ThemeHelper;
3233

3334

@@ -73,9 +74,8 @@ public int onStartCommand(final Intent intent, final int flags, final int startI
7374
}
7475

7576
player.handleIntent(intent);
76-
if (player.getMediaSessionManager() != null) {
77-
player.getMediaSessionManager().handleMediaButtonIntent(intent);
78-
}
77+
player.UIs().get(MediaSessionPlayerUi.class)
78+
.ifPresent(ui -> ui.handleMediaButtonIntent(intent));
7979

8080
return START_NOT_STICKY;
8181
}

app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java renamed to app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionManager.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.schabi.newpipe.player.helper;
1+
package org.schabi.newpipe.player.mediasession;
22

33
import android.content.Context;
44
import android.content.Intent;
@@ -18,8 +18,6 @@
1818
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
1919

2020
import org.schabi.newpipe.MainActivity;
21-
import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
22-
import org.schabi.newpipe.player.mediasession.PlayQueueNavigator;
2321

2422
import java.util.Optional;
2523

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.schabi.newpipe.player.mediasession;
2+
3+
import android.content.Intent;
4+
import android.support.v4.media.session.MediaSessionCompat;
5+
6+
import androidx.annotation.NonNull;
7+
8+
import org.schabi.newpipe.R;
9+
import org.schabi.newpipe.extractor.stream.StreamInfo;
10+
import org.schabi.newpipe.player.Player;
11+
import org.schabi.newpipe.player.playback.PlayerMediaSession;
12+
import org.schabi.newpipe.player.ui.PlayerUi;
13+
import org.schabi.newpipe.util.StreamTypeUtil;
14+
15+
import java.util.Optional;
16+
17+
public class MediaSessionPlayerUi extends PlayerUi {
18+
19+
private MediaSessionManager mediaSessionManager;
20+
21+
public MediaSessionPlayerUi(@NonNull final Player player) {
22+
super(player);
23+
}
24+
25+
@Override
26+
public void initPlayer() {
27+
super.initPlayer();
28+
if (mediaSessionManager != null) {
29+
mediaSessionManager.dispose();
30+
}
31+
mediaSessionManager = new MediaSessionManager(context, player.getExoPlayer(),
32+
new PlayerMediaSession(player));
33+
}
34+
35+
@Override
36+
public void destroyPlayer() {
37+
super.destroyPlayer();
38+
if (mediaSessionManager != null) {
39+
mediaSessionManager.dispose();
40+
mediaSessionManager = null;
41+
}
42+
}
43+
44+
@Override
45+
public void onBroadcastReceived(final Intent intent) {
46+
super.onBroadcastReceived(intent);
47+
// TODO decide whether to handle ACTION_HEADSET_PLUG or not
48+
}
49+
50+
@Override
51+
public void onMetadataChanged(@NonNull final StreamInfo info) {
52+
super.onMetadataChanged(info);
53+
54+
final boolean showThumbnail = player.getPrefs().getBoolean(
55+
context.getString(R.string.show_thumbnail_key), true);
56+
57+
mediaSessionManager.setMetadata(
58+
player.getVideoTitle(),
59+
player.getUploaderName(),
60+
showThumbnail ? Optional.ofNullable(player.getThumbnail()) : Optional.empty(),
61+
StreamTypeUtil.isLiveStream(info.getStreamType()) ? -1 : info.getDuration()
62+
);
63+
}
64+
65+
public void handleMediaButtonIntent(final Intent intent) {
66+
if (mediaSessionManager != null) {
67+
mediaSessionManager.handleMediaButtonIntent(intent);
68+
}
69+
}
70+
71+
public Optional<MediaSessionCompat.Token> getSessionToken() {
72+
return Optional.ofNullable(mediaSessionManager).map(MediaSessionManager::getSessionToken);
73+
}
74+
}

app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
import org.schabi.newpipe.MainActivity;
2020
import org.schabi.newpipe.R;
2121
import org.schabi.newpipe.player.Player;
22+
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
2223
import org.schabi.newpipe.util.NavigationHelper;
2324

2425
import java.util.List;
2526

2627
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
28+
import static androidx.media.app.NotificationCompat.MediaStyle;
2729
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
2830
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
2931
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_CLOSE;
@@ -101,9 +103,11 @@ private synchronized NotificationCompat.Builder createNotification() {
101103
player.getContext(), player.getPrefs(), nonNothingSlotCount);
102104
final int[] compactSlots = compactSlotList.stream().mapToInt(Integer::intValue).toArray();
103105

104-
builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
105-
.setMediaSession(player.getMediaSessionManager().getSessionToken())
106-
.setShowActionsInCompactView(compactSlots))
106+
final MediaStyle mediaStyle = new MediaStyle().setShowActionsInCompactView(compactSlots);
107+
player.UIs().get(MediaSessionPlayerUi.class).flatMap(MediaSessionPlayerUi::getSessionToken)
108+
.ifPresent(mediaStyle::setMediaSession);
109+
110+
builder.setStyle(mediaStyle)
107111
.setPriority(NotificationCompat.PRIORITY_HIGH)
108112
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
109113
.setCategory(NotificationCompat.CATEGORY_TRANSPORT)

app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ public abstract class PlayerUi {
2929
@NonNull protected final Player player;
3030

3131
/**
32-
* @param player the player instance that will be usable throughout the lifetime of this UI
32+
* @param player the player instance that will be usable throughout the lifetime of this UI; its
33+
* context should already have been initialized
3334
*/
3435
protected PlayerUi(@NonNull final Player player) {
3536
this.context = player.getContext();

app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,19 @@
88
public final class PlayerUiList {
99
final List<PlayerUi> playerUis = new ArrayList<>();
1010

11+
/**
12+
* Creates a {@link PlayerUiList} starting with the provided player uis. The provided player uis
13+
* will not be prepared like those passed to {@link #addAndPrepare(PlayerUi)}, because when
14+
* the {@link PlayerUiList} constructor is called, the player is still not running and it
15+
* wouldn't make sense to initialize uis then. Instead the player will initialize them by doing
16+
* proper calls to {@link #call(Consumer)}.
17+
*
18+
* @param initialPlayerUis the player uis this list should start with; the order will be kept
19+
*/
20+
public PlayerUiList(final PlayerUi... initialPlayerUis) {
21+
playerUis.addAll(List.of(initialPlayerUis));
22+
}
23+
1124
/**
1225
* Adds the provided player ui to the list and calls on it the initialization functions that
1326
* apply based on the current player state. The preparation step needs to be done since when UIs
@@ -67,11 +80,11 @@ public <T> Optional<T> get(final Class<T> playerUiType) {
6780
}
6881

6982
/**
70-
* Calls the provided consumer on all player UIs in the list.
83+
* Calls the provided consumer on all player UIs in the list, in order of addition.
7184
* @param consumer the consumer to call with player UIs
7285
*/
7386
public void call(final Consumer<PlayerUi> consumer) {
7487
//noinspection SimplifyStreamApiCallChains
75-
playerUis.stream().forEach(consumer);
88+
playerUis.stream().forEachOrdered(consumer);
7689
}
7790
}

0 commit comments

Comments
 (0)