mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Start playback from notification
This change fixes two bugs where MediaSessionServe shows a notification with the Play icon but tapping it will not start playback: 1. After playback ends: we need to seek to the beginning of the media item. 2. After adding media items to the player but not starting playback: We need to call Player.prepare() too. PiperOrigin-RevId: 432469953 (cherry picked from commit 1023b9d55efe8f0470c5f3b75cd84e40860f79be)
This commit is contained in:
parent
4456a865cc
commit
c56c6a2ea4
@ -30,6 +30,7 @@ import android.widget.ListView
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.session.MediaBrowser
|
import androidx.media3.session.MediaBrowser
|
||||||
import androidx.media3.session.SessionToken
|
import androidx.media3.session.SessionToken
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
@ -179,6 +180,9 @@ class PlayableFolderActivity : AppCompatActivity() {
|
|||||||
returnConvertView.findViewById<TextView>(R.id.add_button).setOnClickListener {
|
returnConvertView.findViewById<TextView>(R.id.add_button).setOnClickListener {
|
||||||
val browser = this@PlayableFolderActivity.browser ?: return@setOnClickListener
|
val browser = this@PlayableFolderActivity.browser ?: return@setOnClickListener
|
||||||
browser.addMediaItem(mediaItem)
|
browser.addMediaItem(mediaItem)
|
||||||
|
if (browser.playbackState == Player.STATE_IDLE) {
|
||||||
|
browser.prepare()
|
||||||
|
}
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
findViewById<LinearLayout>(R.id.linear_layout),
|
findViewById<LinearLayout>(R.id.linear_layout),
|
||||||
getString(R.string.added_media_item_format, mediaItem.mediaMetadata.title),
|
getString(R.string.added_media_item_format, mediaItem.mediaMetadata.title),
|
||||||
|
@ -96,7 +96,6 @@ class PlaybackService : MediaLibraryService() {
|
|||||||
|
|
||||||
val item = MediaItemTree.getItemFromTitle(mediaTitle) ?: MediaItemTree.getRandomItem()
|
val item = MediaItemTree.getItemFromTitle(mediaTitle) ?: MediaItemTree.getRandomItem()
|
||||||
player.setMediaItem(item)
|
player.setMediaItem(item)
|
||||||
player.prepare()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSetMediaUri(
|
override fun onSetMediaUri(
|
||||||
|
@ -27,6 +27,7 @@ import android.os.Bundle;
|
|||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.graphics.drawable.IconCompat;
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
import androidx.media3.common.MediaMetadata;
|
import androidx.media3.common.MediaMetadata;
|
||||||
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
|
||||||
@ -93,20 +94,21 @@ import androidx.media3.common.util.Util;
|
|||||||
IconCompat.createWithResource(context, R.drawable.media3_notification_seek_to_previous),
|
IconCompat.createWithResource(context, R.drawable.media3_notification_seek_to_previous),
|
||||||
context.getString(R.string.media3_controls_seek_to_previous_description),
|
context.getString(R.string.media3_controls_seek_to_previous_description),
|
||||||
MediaNotification.ActionFactory.COMMAND_SKIP_TO_PREVIOUS));
|
MediaNotification.ActionFactory.COMMAND_SKIP_TO_PREVIOUS));
|
||||||
if (mediaController.getPlayWhenReady()) {
|
if (mediaController.getPlaybackState() == Player.STATE_ENDED
|
||||||
// Pause action.
|
|| !mediaController.getPlayWhenReady()) {
|
||||||
builder.addAction(
|
|
||||||
actionFactory.createMediaAction(
|
|
||||||
IconCompat.createWithResource(context, R.drawable.media3_notification_pause),
|
|
||||||
context.getString(R.string.media3_controls_pause_description),
|
|
||||||
MediaNotification.ActionFactory.COMMAND_PAUSE));
|
|
||||||
} else {
|
|
||||||
// Play action.
|
// Play action.
|
||||||
builder.addAction(
|
builder.addAction(
|
||||||
actionFactory.createMediaAction(
|
actionFactory.createMediaAction(
|
||||||
IconCompat.createWithResource(context, R.drawable.media3_notification_play),
|
IconCompat.createWithResource(context, R.drawable.media3_notification_play),
|
||||||
context.getString(R.string.media3_controls_play_description),
|
context.getString(R.string.media3_controls_play_description),
|
||||||
MediaNotification.ActionFactory.COMMAND_PLAY));
|
MediaNotification.ActionFactory.COMMAND_PLAY));
|
||||||
|
} else {
|
||||||
|
// Pause action.
|
||||||
|
builder.addAction(
|
||||||
|
actionFactory.createMediaAction(
|
||||||
|
IconCompat.createWithResource(context, R.drawable.media3_notification_pause),
|
||||||
|
context.getString(R.string.media3_controls_pause_description),
|
||||||
|
MediaNotification.ActionFactory.COMMAND_PAUSE));
|
||||||
}
|
}
|
||||||
// Skip to next action.
|
// Skip to next action.
|
||||||
builder.addAction(
|
builder.addAction(
|
||||||
|
@ -196,7 +196,9 @@ import java.util.concurrent.TimeoutException;
|
|||||||
@Override
|
@Override
|
||||||
public void onEvents(Player player, Player.Events events) {
|
public void onEvents(Player player, Player.Events events) {
|
||||||
if (events.containsAny(
|
if (events.containsAny(
|
||||||
Player.EVENT_PLAY_WHEN_READY_CHANGED, Player.EVENT_MEDIA_METADATA_CHANGED)) {
|
Player.EVENT_PLAYBACK_STATE_CHANGED,
|
||||||
|
Player.EVENT_PLAY_WHEN_READY_CHANGED,
|
||||||
|
Player.EVENT_MEDIA_METADATA_CHANGED)) {
|
||||||
updateNotification(session);
|
updateNotification(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE;
|
|||||||
import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE;
|
import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE;
|
||||||
import static androidx.media3.common.Player.COMMAND_SET_SPEED_AND_PITCH;
|
import static androidx.media3.common.Player.COMMAND_SET_SPEED_AND_PITCH;
|
||||||
import static androidx.media3.common.Player.COMMAND_STOP;
|
import static androidx.media3.common.Player.COMMAND_STOP;
|
||||||
|
import static androidx.media3.common.Player.STATE_ENDED;
|
||||||
|
import static androidx.media3.common.Player.STATE_IDLE;
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||||
import static androidx.media3.common.util.Util.postOrRun;
|
import static androidx.media3.common.util.Util.postOrRun;
|
||||||
@ -231,7 +233,17 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
} else {
|
} else {
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
dispatchSessionTaskWithPlayerCommand(
|
||||||
COMMAND_PLAY_PAUSE,
|
COMMAND_PLAY_PAUSE,
|
||||||
(controller) -> sessionImpl.getPlayerWrapper().play(),
|
(controller) -> {
|
||||||
|
PlayerWrapper playerWrapper = sessionImpl.getPlayerWrapper();
|
||||||
|
@Player.State int playbackState = playerWrapper.getPlaybackState();
|
||||||
|
if (playbackState == STATE_IDLE) {
|
||||||
|
playerWrapper.prepare();
|
||||||
|
} else if (playbackState == STATE_ENDED) {
|
||||||
|
playerWrapper.seekTo(
|
||||||
|
playerWrapper.getCurrentMediaItemIndex(), /* positionMs= */ C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
playerWrapper.play();
|
||||||
|
},
|
||||||
remoteUserInfo);
|
remoteUserInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,7 +297,17 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
public void onPlay() {
|
public void onPlay() {
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
dispatchSessionTaskWithPlayerCommand(
|
||||||
COMMAND_PLAY_PAUSE,
|
COMMAND_PLAY_PAUSE,
|
||||||
controller -> sessionImpl.getPlayerWrapper().play(),
|
controller -> {
|
||||||
|
PlayerWrapper playerWrapper = sessionImpl.getPlayerWrapper();
|
||||||
|
@Player.State int playbackState = playerWrapper.getPlaybackState();
|
||||||
|
if (playbackState == Player.STATE_IDLE) {
|
||||||
|
playerWrapper.prepare();
|
||||||
|
} else if (playbackState == Player.STATE_ENDED) {
|
||||||
|
playerWrapper.seekTo(
|
||||||
|
playerWrapper.getCurrentMediaItemIndex(), /* positionMs= */ C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
playerWrapper.play();
|
||||||
|
},
|
||||||
sessionCompat.getCurrentControllerInfo());
|
sessionCompat.getCurrentControllerInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +343,15 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
if (sessionImpl.onSetMediaUriOnHandler(
|
if (sessionImpl.onSetMediaUriOnHandler(
|
||||||
controller, mediaUri, extras == null ? Bundle.EMPTY : extras)
|
controller, mediaUri, extras == null ? Bundle.EMPTY : extras)
|
||||||
== RESULT_SUCCESS) {
|
== RESULT_SUCCESS) {
|
||||||
sessionImpl.getPlayerWrapper().play();
|
PlayerWrapper playerWrapper = sessionImpl.getPlayerWrapper();
|
||||||
|
@Player.State int playbackState = playerWrapper.getPlaybackState();
|
||||||
|
if (playbackState == Player.STATE_IDLE) {
|
||||||
|
playerWrapper.prepare();
|
||||||
|
} else if (playbackState == STATE_ENDED) {
|
||||||
|
playerWrapper.seekTo(
|
||||||
|
playerWrapper.getCurrentMediaItemIndex(), /* positionMs= */ C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
playerWrapper.play();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user