From 0f59e337be30addd6d1adff9d355c0bf9da4164c Mon Sep 17 00:00:00 2001 From: litingting Date: Thu, 26 Sep 2024 19:06:05 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=9E=E7=BB=AD=E6=92=AD=E6=94=BE=EF=BC=8C?= =?UTF-8?q?=E5=89=8D=E5=90=8E=E5=88=87=E6=AD=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 + app/src/main/AndroidManifest.xml | 1 + .../player/api/MediaControllerListener.java | 14 ++ .../player/api/onImageColorListener.java | 5 + .../hi/music/player/dialog/BaseDialog.java | 61 +++++ .../music/player/dialog/DialogPlayList.java | 20 ++ .../hi/music/player/helper/CommonUtils.java | 46 ++++ .../player/javabean/CustomerUrlInfo.java | 35 +++ .../response/ResponsePlayListInfo.java | 15 +- .../media3/MyMediaControllerManager.java | 229 ++++++++++++------ .../music/player/media3/PlaybackService.java | 62 +++-- .../hi/music/player/network/JsonHelper.java | 34 ++- .../player/ui/activity/PlayActivity.java | 122 +++++++--- .../player/ui/activity/viewmodel/VMPlay.java | 26 +- app/src/main/res/layout/activity_play.xml | 9 +- app/src/main/res/layout/dialog_play_list.xml | 9 + 16 files changed, 535 insertions(+), 155 deletions(-) create mode 100644 app/src/main/java/com/hi/music/player/api/onImageColorListener.java create mode 100644 app/src/main/java/com/hi/music/player/dialog/BaseDialog.java create mode 100644 app/src/main/java/com/hi/music/player/dialog/DialogPlayList.java create mode 100644 app/src/main/java/com/hi/music/player/javabean/CustomerUrlInfo.java create mode 100644 app/src/main/res/layout/dialog_play_list.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 53ee459..be3cce7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -57,6 +57,8 @@ dependencies { implementation("com.github.bumptech.glide:glide:4.16.0") + implementation ("androidx.palette:palette:1.0.0") + //----------media3 implementation("androidx.media3:media3-exoplayer:1.4.1") implementation("androidx.media3:media3-exoplayer-dash:1.4.1") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2412e32..dd79058 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> + diff --git a/app/src/main/java/com/hi/music/player/api/MediaControllerListener.java b/app/src/main/java/com/hi/music/player/api/MediaControllerListener.java index 57bf9bc..c1d618a 100644 --- a/app/src/main/java/com/hi/music/player/api/MediaControllerListener.java +++ b/app/src/main/java/com/hi/music/player/api/MediaControllerListener.java @@ -1,8 +1,22 @@ package com.hi.music.player.api; +import androidx.media3.common.MediaItem; + public interface MediaControllerListener { void onPlayStatus(int playStatus); + + + /** + * + * @param videoId + * @param playListIndex 在播放列表中的位置索引 + * @param playNow 立即播放 + */ + void onRequestNextUri(String videoId,int playListIndex,boolean playNow); + + + void onChangeMusic(MediaItem mediaItem); } diff --git a/app/src/main/java/com/hi/music/player/api/onImageColorListener.java b/app/src/main/java/com/hi/music/player/api/onImageColorListener.java new file mode 100644 index 0000000..30194d4 --- /dev/null +++ b/app/src/main/java/com/hi/music/player/api/onImageColorListener.java @@ -0,0 +1,5 @@ +package com.hi.music.player.api; + +public interface onImageColorListener { + void onImageColor(int color); +} diff --git a/app/src/main/java/com/hi/music/player/dialog/BaseDialog.java b/app/src/main/java/com/hi/music/player/dialog/BaseDialog.java new file mode 100644 index 0000000..85f9169 --- /dev/null +++ b/app/src/main/java/com/hi/music/player/dialog/BaseDialog.java @@ -0,0 +1,61 @@ +package com.hi.music.player.dialog; + + +import android.app.Dialog; +import android.os.Bundle; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.viewbinding.ViewBinding; + + +public abstract class BaseDialog extends DialogFragment { + + protected T vb; + + + protected abstract T getViewBinding(LayoutInflater inflater, ViewGroup container); + + protected abstract void initView(); + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + vb = getViewBinding(inflater,container); + init(); + initView(); + return vb.getRoot(); + } + + + private void init() { + + Dialog dialog = getDialog(); + setCancelable(true); + if (dialog != null) { + Window window = dialog.getWindow(); + if (window != null) { +// window.setBackgroundDrawableResource(); + window.getDecorView().setPadding(0, 0, 0, 0); + + WindowManager.LayoutParams attributes = window.getAttributes(); + attributes.gravity = Gravity.BOTTOM; + attributes.width = WindowManager.LayoutParams.MATCH_PARENT; + attributes.height = WindowManager.LayoutParams.WRAP_CONTENT; + window.setAttributes(attributes); + } + } + + } + + public void closeDialog() { + dismiss(); + } + +} diff --git a/app/src/main/java/com/hi/music/player/dialog/DialogPlayList.java b/app/src/main/java/com/hi/music/player/dialog/DialogPlayList.java new file mode 100644 index 0000000..3b1927c --- /dev/null +++ b/app/src/main/java/com/hi/music/player/dialog/DialogPlayList.java @@ -0,0 +1,20 @@ +package com.hi.music.player.dialog; + +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import com.hi.music.player.databinding.DialogPlayListBinding; + +public class DialogPlayList extends BaseDialog{ + @Override + protected DialogPlayListBinding getViewBinding(LayoutInflater inflater, ViewGroup container) { + return DialogPlayListBinding.inflate(inflater,container,false); + } + + @Override + protected void initView() { + + } + + +} diff --git a/app/src/main/java/com/hi/music/player/helper/CommonUtils.java b/app/src/main/java/com/hi/music/player/helper/CommonUtils.java index 4d0fc47..b3ca57c 100644 --- a/app/src/main/java/com/hi/music/player/helper/CommonUtils.java +++ b/app/src/main/java/com/hi/music/player/helper/CommonUtils.java @@ -1,10 +1,17 @@ package com.hi.music.player.helper; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.util.DisplayMetrics; import android.util.Log; +import android.widget.ImageView; + +import androidx.palette.graphics.Palette; import com.hi.music.player.MusicApplication; +import com.hi.music.player.api.onImageColorListener; import org.json.JSONException; import org.json.JSONObject; @@ -80,4 +87,43 @@ public class CommonUtils { long minutes = (millis / (1000 * 60)) % 60; return String.format("%d:%02d", minutes, seconds); // 格式化为 mm:ss } + + /** + * 从图片中提取主色调 + * @param imDraw + */ + public static void extractDominantColor(Drawable imDraw, onImageColorListener listener) { + BitmapDrawable drawable = (BitmapDrawable)imDraw; + if (drawable != null) { + Bitmap bitmap = drawable.getBitmap(); + + // 使用 Palette 提取颜色 + Palette.from(bitmap).generate(palette -> { + if (palette != null) { + int dominantColor = palette.getDominantColor(0); + int suitableDarkColor = getSuitableDarkColor(dominantColor); + listener.onImageColor(suitableDarkColor); + } + }); + } + } + + + private static int getSuitableDarkColor(int color) { + // 提取颜色的 R, G, B 值 + int r = (color >> 16) & 0xff; + int g = (color >> 8) & 0xff; + int b = color & 0xff; + + // 计算亮度 + double luminance = 0.299 * r + 0.587 * g + 0.114 * b; + + // 如果亮度较高,则选择更深的颜色 + if (luminance > 128) { + return 0xFF000000; // 黑色 + } else { + // 如果颜色较暗,选择一种深色调 + return 0xFF1F1F1F; // 深灰色作为替代 + } + } } diff --git a/app/src/main/java/com/hi/music/player/javabean/CustomerUrlInfo.java b/app/src/main/java/com/hi/music/player/javabean/CustomerUrlInfo.java new file mode 100644 index 0000000..379ee49 --- /dev/null +++ b/app/src/main/java/com/hi/music/player/javabean/CustomerUrlInfo.java @@ -0,0 +1,35 @@ +package com.hi.music.player.javabean; + +import com.hi.music.player.javabean.response.ResponsePlayUrl; + +public class CustomerUrlInfo { + + private ResponsePlayUrl playUrl; + private int playMusicIndex; + private boolean needPlayNow; + + + public ResponsePlayUrl getPlayUrl() { + return playUrl; + } + + public void setPlayUrl(ResponsePlayUrl playUrl) { + this.playUrl = playUrl; + } + + public int getPlayMusicIndex() { + return playMusicIndex; + } + + public void setPlayMusicIndex(int playMusicIndex) { + this.playMusicIndex = playMusicIndex; + } + + public boolean isNeedPlayNow() { + return needPlayNow; + } + + public void setNeedPlayNow(boolean needPlayNow) { + this.needPlayNow = needPlayNow; + } +} diff --git a/app/src/main/java/com/hi/music/player/javabean/response/ResponsePlayListInfo.java b/app/src/main/java/com/hi/music/player/javabean/response/ResponsePlayListInfo.java index 0ecf236..bc3b4ce 100644 --- a/app/src/main/java/com/hi/music/player/javabean/response/ResponsePlayListInfo.java +++ b/app/src/main/java/com/hi/music/player/javabean/response/ResponsePlayListInfo.java @@ -4,6 +4,11 @@ public class ResponsePlayListInfo { //封面 private String covert; + + + //小尺寸封面 + private String smallCovert; + //歌曲名字 private String SongTitle; @@ -37,11 +42,13 @@ public class ResponsePlayListInfo { private String audioUrlMedium; + public String getSmallCovert() { + return smallCovert; + } - - - - + public void setSmallCovert(String smallCovert) { + this.smallCovert = smallCovert; + } public long getDurationMs() { return DurationMs; diff --git a/app/src/main/java/com/hi/music/player/media3/MyMediaControllerManager.java b/app/src/main/java/com/hi/music/player/media3/MyMediaControllerManager.java index b60d6e4..9f58d9a 100644 --- a/app/src/main/java/com/hi/music/player/media3/MyMediaControllerManager.java +++ b/app/src/main/java/com/hi/music/player/media3/MyMediaControllerManager.java @@ -1,7 +1,9 @@ package com.hi.music.player.media3; import android.content.ComponentName; +import android.net.Uri; +import androidx.annotation.Nullable; import androidx.annotation.OptIn; import androidx.media3.common.MediaItem; import androidx.media3.common.MediaMetadata; @@ -23,7 +25,9 @@ import com.hi.music.player.javabean.response.ResponsePlayUrl; import com.hi.music.player.network.RetrofitManager; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.concurrent.ExecutionException; public class MyMediaControllerManager { @@ -32,6 +36,11 @@ public class MyMediaControllerManager { private MediaController mediaController; + private MediaControllerListener mListener; + + //播放列表总数量 + private List playList; + public static MyMediaControllerManager getInstance() { if (myMediaControllerManagerInstance == null) { synchronized (RetrofitManager.class) { @@ -68,36 +77,60 @@ public class MyMediaControllerManager { } public void addListener(MediaControllerListener listener) { + mListener = listener; mediaController.addListener(new Player.Listener() { @Override public void onPlayerError(PlaybackException error) { CommonUtils.LogMsg("=-----PlaybackException+" + error.getMessage()); - listener.onPlayStatus(MyValue.PLAY_STATUS_CODE); + mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE); + } + + @Override + public void onMediaItemTransition(@Nullable MediaItem mediaItem, int reason) { + //当前媒体项发生变化,切歌 + if(mediaItem == null){ + //第二次进入PlayActitivity ,调用resetPlayList(),这里为null + return; + } + mListener.onChangeMusic(mediaItem); } @Override public void onIsPlayingChanged(boolean isPlaying) { - CommonUtils.LogMsg("-----onIsPlayingChanged+" + isPlaying); + if (isPlaying) { + + // TODO: 2024/9/26 自动播放完成切歌到下一首播放没有触发这里请求下一首 // 播放器开始播放 - System.out.println("Playback started!"); + MediaItem currentItem = mediaController.getCurrentMediaItem(); + int currentMediaItemIndex = mediaController.getCurrentMediaItemIndex(); + if (currentMediaItemIndex < playList.size() - 1) { + //代表有下一首 + if (!mediaController.hasNextMediaItem()) { + //没有更新下一首的uri + CommonUtils.LogMsg("----0000000000-请求下一首的uri" + mediaController.getMediaItemCount()); + int nextIndex = currentMediaItemIndex + 1; + mListener.onRequestNextUri(playList.get(nextIndex).getVideoId(), nextIndex,false); + + } + } } else { // 播放器暂停或停止 - System.out.println("Playback paused or stopped."); + } } @Override public void onPlaybackStateChanged(int playbackState) { - - listener.onPlayStatus(playbackState); + CommonUtils.LogMsg("----playbackState" + playbackState + "------------" + mediaController.getMediaItemCount()); + mListener.onPlayStatus(playbackState); } @Override public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) { // 快进、快退等操作 - CommonUtils.LogMsg("=-----快进、快退+" + newPosition.positionMs); +// CommonUtils.LogMsg("=-----快进、快退+" + newPosition.positionMs); // mediaControllerListener.onPlayStatus(playbackState); } }); @@ -119,95 +152,153 @@ public class MyMediaControllerManager { } +// /** +// * 更新播放列表中的音频url +// * +// * @param playUrl +// */ +// public void UpdateAudioUrl(ResponsePlayUrl playUrl) { +// +// CommonUtils.LogMsg("-------------更新播放列表中的音频 mediaController.getMediaItemCount()=" + mediaController.getMediaItemCount()); +// for (int i = 0; i < mediaController.getMediaItemCount(); i++) { +// MediaItem mediaItemAt = mediaController.getMediaItemAt(i); +// if (mediaItemAt.mediaId.equals(playUrl.getVideoId())) { +// +// MediaItem.Builder builder = mediaItemAt.buildUpon(); +//// mediaController.removeMediaItem(i); +//// MediaItem.Builder builder = new MediaItem.Builder(); +// builder.setMediaId(playUrl.getVideoId()); +// if (playUrl.getAudioUrlMedium() != null) { +// builder.setUri(playUrl.getAudioUrlMedium()); +// } else { +// builder.setUri(playUrl.getAudioUrlLow()); +// } +// mediaController.replaceMediaItem(i, builder.build()); +// CharSequence title = mediaController.getMediaItemAt(i).mediaMetadata.title; +// CommonUtils.LogMsg("-------------更新播放列表中的音频url= i=" + i + "---title=" + title + "----mediaController.size=" + mediaController.getMediaItemCount() + "---" + mediaController); +// break; +// } +// } +// } + + public void setPlayList(List playList) { + this.playList = playList; + } + + public void resetPlayList(){ + mediaController.clearMediaItems(); + } + /** - * 更新播放列表中的音频url + * 添加播放列表(不带音频url) + * 注意没有更新有效uri的不会被实际添加到mediaController * * @param playUrl */ @OptIn(markerClass = UnstableApi.class) - public void UpdateAudioUrl(ResponsePlayUrl playUrl) { - for (int i = 0; i < mediaController.getMediaItemCount(); i++) { - MediaItem mediaItemAt = mediaController.getMediaItemAt(i); - if (mediaItemAt.mediaId.equals(playUrl.getVideoId())) { - MediaItem.Builder builder = mediaItemAt.buildUpon(); + public void addMusicToPlayList(ResponsePlayUrl playUrl, int playListIndex) { + if (playListIndex < playList.size()&& playListIndex>=mediaController.getMediaItemCount()) { + ResponsePlayListInfo listInfo = playList.get(playListIndex); + if (listInfo.getVideoId().equals(playUrl.getVideoId())) { + MediaItem.Builder builder = new MediaItem.Builder(); + + //唯一标识符 + builder.setMediaId(playUrl.getVideoId()); if (playUrl.getAudioUrlMedium() != null) { builder.setUri(playUrl.getAudioUrlMedium()); } else { builder.setUri(playUrl.getAudioUrlLow()); } - mediaController.setMediaItem(builder.build(), i); - CharSequence title = mediaController.getMediaItemAt(i).mediaMetadata.title; - CommonUtils.LogMsg("-------------更新播放列表中的音频url= i=" + i + "---title=" + title); - break; + + MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder(); + + MediaMetadata_builder.setArtist(listInfo.getSingerName()); + + /** + * 这里使用setDescription保存歌曲时长的分秒字符串 + */ + MediaMetadata_builder.setDescription(listInfo.getDuration()); + MediaMetadata_builder.setDurationMs(listInfo.getDurationMs()); + MediaMetadata_builder.setArtworkUri(Uri.parse(listInfo.getCovert())); +// MediaMetadata_builder.setArtworkUri(Uri.parse("https://t7.baidu.com/it/u=2604797219,1573897854&fm=193&f=GIF")); + MediaMetadata_builder.setTitle(listInfo.getSongTitle()); + + CommonUtils.LogMsg("----------添加到播放列表 i=" + playListIndex + "---" + listInfo.getSongTitle() + "-------VideoId=" + listInfo.getVideoId()); +// MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear())); + builder.setMediaMetadata(MediaMetadata_builder.build()); + mediaController.addMediaItem(builder.build()); } } } + +// /** +// * 添加播放列表(不带音频url) +// * 注意没有更新有效uri的不会被实际添加到mediaController +// * +// * @param listInfo +// */ // @OptIn(markerClass = UnstableApi.class) -// public void addMusicPlay(ResponsePlayListInfo playInfo, ResponsePlayUrl responsePlay) { +// public void addMusicPlayList(List listInfo) { +// playList = listInfo; // List mediaItems = new ArrayList<>(); -// MediaItem.Builder builder = new MediaItem.Builder(); -// if (responsePlay.getAudioUrlMedium() != null) { -// builder.setUri(responsePlay.getAudioUrlMedium()); -// } else { -// builder.setUri(responsePlay.getAudioUrlLow()); -// } +// for (int i = 0; i < listInfo.size(); i++) { +// ResponsePlayListInfo playInfo = listInfo.get(i); // -// //唯一标识符 -// builder.setMediaId(responsePlay.getVideoId()); +// MediaItem.Builder builder = new MediaItem.Builder(); // -// MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder(); +// //唯一标识符 +// builder.setMediaId(playInfo.getVideoId()); // -// MediaMetadata_builder.setArtist(playInfo.getSingerName()); -// MediaMetadata_builder.setDurationMs(playInfo.getDurationMs()); -// MediaMetadata_builder.setAlbumArtist(playInfo.getCovert()); -// MediaMetadata_builder.setTitle(playInfo.getSongTitle()); +// MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder(); +// +// MediaMetadata_builder.setArtist(playInfo.getSingerName()); +// MediaMetadata_builder.setDurationMs(playInfo.getDurationMs()); +//// MediaMetadata_builder.setArtworkUri(Uri.parse(playInfo.getCovert())); +// MediaMetadata_builder.setArtworkUri(Uri.parse("https://t7.baidu.com/it/u=2604797219,1573897854&fm=193&f=GIF")); +// MediaMetadata_builder.setTitle(playInfo.getSongTitle()); +// +// CommonUtils.LogMsg("----------添加播放列表 i=" + i + "---" + playInfo.getSongTitle() + "-------VideoId=" + playInfo.getVideoId()); //// MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear())); -// builder.setMediaMetadata(MediaMetadata_builder.build()); -// -// mediaItems.add(builder.build()); -// mediaController.addMediaItems(mediaItems); -// mediaController.prepare(); -// +// builder.setMediaMetadata(MediaMetadata_builder.build()); +// mediaController.addMediaItem(builder.build()); +//// mediaItems.add(builder.build()); +// } +//// mediaController.setMediaItems(mediaItems); // } - - /** - * 添加播放列表(不带音频url) - * - * @param listInfo - */ - @OptIn(markerClass = UnstableApi.class) - public void addMusicPlayList(List listInfo) { - List mediaItems = new ArrayList<>(); - for (int i = 0; i < listInfo.size(); i++) { - ResponsePlayListInfo playInfo = listInfo.get(i); - - MediaItem.Builder builder = new MediaItem.Builder(); - - //唯一标识符 - builder.setMediaId(playInfo.getVideoId()); - - MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder(); - - MediaMetadata_builder.setArtist(playInfo.getSingerName()); - MediaMetadata_builder.setDurationMs(playInfo.getDurationMs()); - MediaMetadata_builder.setAlbumArtist(playInfo.getCovert()); - MediaMetadata_builder.setTitle(playInfo.getSongTitle()); -// MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear())); - builder.setMediaMetadata(MediaMetadata_builder.build()); - mediaItems.add(builder.build()); - } - mediaController.addMediaItems(mediaItems); - } - public void play() { - mediaController.prepare(); - if (!mediaController.isPlaying()) + if (!mediaController.isPlaying()) { + mediaController.prepare(); mediaController.play(); + } + } public void pause() { if (mediaController.isPlaying()) mediaController.pause(); } + + public void playNext() { + if (mediaController.hasNextMediaItem()) { + mediaController.seekToNextMediaItem(); + } else { + int currentMediaItemIndex = mediaController.getCurrentMediaItemIndex(); + if (currentMediaItemIndex < playList.size() - 1) { + //应该有下一首,可能是歌曲url请求失败,需要重新请求 + int nextIndex = currentMediaItemIndex + 1; + mListener.onRequestNextUri(playList.get(nextIndex).getVideoId(), nextIndex,true); + CommonUtils.LogMsg("-------------应该有下一首,可能是歌曲url请求失败,需要重新请求"); + } + } + } + + public void playPrevious() { + if (mediaController.hasPreviousMediaItem()) { + mediaController.seekToPreviousMediaItem(); + } else { + mediaController.seekTo(0); + mediaController.play(); + } + } } diff --git a/app/src/main/java/com/hi/music/player/media3/PlaybackService.java b/app/src/main/java/com/hi/music/player/media3/PlaybackService.java index 32d17fa..6ebcf2c 100644 --- a/app/src/main/java/com/hi/music/player/media3/PlaybackService.java +++ b/app/src/main/java/com/hi/music/player/media3/PlaybackService.java @@ -4,11 +4,13 @@ import android.content.Intent; import androidx.annotation.Nullable; +import androidx.annotation.OptIn; import androidx.media3.common.AudioAttributes; import androidx.media3.common.C; import androidx.media3.common.MediaItem; import androidx.media3.common.MediaMetadata; import androidx.media3.common.Player; +import androidx.media3.common.util.UnstableApi; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.source.DefaultMediaSourceFactory; @@ -17,6 +19,7 @@ import androidx.media3.session.MediaSession; import androidx.media3.session.MediaSessionService; import com.google.common.util.concurrent.ListenableFuture; +import com.hi.music.player.R; import com.hi.music.player.helper.CommonUtils; import com.hi.music.player.javabean.response.ResponsePlayUrl; @@ -31,32 +34,43 @@ public class PlaybackService extends MediaSessionService { public void onCreate() { super.onCreate(); - AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(AudioAttributes.DEFAULT.usage) - .setContentType(AudioAttributes.DEFAULT.contentType) - .build(); - -// MediaSource.Factory mediaSourceFactory = -// new DefaultMediaSourceFactory(context) -// .setDataSourceFactory(cacheDataSourceFactory) -// .setLocalAdInsertionComponents(adsLoaderProvider); - - player = new ExoPlayer.Builder(this) - .setWakeMode(C.WAKE_MODE_LOCAL) -// .setMediaSourceFactory(mediaSourceFactory) - .setAudioAttributes(audioAttributes, true).build(); - - mediaSession = new MediaSession.Builder(this, player).setCallback(new MediaSession.Callback() { + player = new ExoPlayer.Builder(this).build(); + mediaSession = new MediaSession.Builder(this, player) + .setCallback(new MediaSession.Callback() { @Override public ListenableFuture> onAddMediaItems(MediaSession mediaSession, MediaSession.ControllerInfo controller, List mediaItems) { - CommonUtils.LogMsg("--------mediaItems="+mediaItems.get(0).mediaMetadata.title); -// player.addMediaItems(mediaItems); - + CommonUtils.LogMsg("--------实际添加的媒体项="+mediaItems.size()+"----"+mediaSession.getPlayer().getMediaItemCount()); return MediaSession.Callback.super.onAddMediaItems(mediaSession, controller, mediaItems); } + + + }) .build(); +// player = new ExoPlayer.Builder(this) +// .setWakeMode(C.WAKE_MODE_LOCAL) +//// .setMediaSourceFactory(mediaSourceFactory) +// .setAudioAttributes(audioAttributes, true).build(); +// +// mediaSession = new MediaSession.Builder(this, player) +// .setId(getString(R.string.app_name) + "_MusicId") +// .setCallback(new MediaSession.Callback() { +// @Override +// public ListenableFuture> onAddMediaItems(MediaSession mediaSession, MediaSession.ControllerInfo controller, List mediaItems) { +// +// CommonUtils.LogMsg("--------实际添加的媒体项="+player.getMediaItemCount()); +//// player.addMediaItems(mediaItems); +// +// return MediaSession.Callback.super.onAddMediaItems(mediaSession, controller, mediaItems); +// } +// }) +// .build(); + + + + } @@ -71,11 +85,13 @@ public class PlaybackService extends MediaSessionService { @Override public void onTaskRemoved(@Nullable Intent rootIntent) { Player player = mediaSession.getPlayer(); -// if (player.getPlayWhenReady()) { -// // Make sure the service is not in foreground. -// player.pause(); -// } -// stopSelf(); + if (!player.getPlayWhenReady() + || player.getMediaItemCount() == 0 + || player.getPlaybackState() == Player.STATE_ENDED) { + // Stop the service if not playing, continue playing in the background + // otherwise. + stopSelf(); + } } @Override diff --git a/app/src/main/java/com/hi/music/player/network/JsonHelper.java b/app/src/main/java/com/hi/music/player/network/JsonHelper.java index 8fed38a..35443c9 100644 --- a/app/src/main/java/com/hi/music/player/network/JsonHelper.java +++ b/app/src/main/java/com/hi/music/player/network/JsonHelper.java @@ -22,7 +22,7 @@ public class JsonHelper { public static ResponseHome ResolveHomeJson(JSONObject jsonObject) { ResponseHome responseHome = new ResponseHome(); try { - String bgUrl = getJsonUrl(jsonObject.getJSONObject("background")); + String bgUrl = getJsonUrl(jsonObject.getJSONObject("background"),true); JSONObject sectionListRenderer = jsonObject.getJSONObject("contents").getJSONObject("singleColumnBrowseResultsRenderer").getJSONArray("tabs").getJSONObject(0).getJSONObject("tabRenderer").getJSONObject("content").getJSONObject("sectionListRenderer"); @@ -106,7 +106,7 @@ public class JsonHelper { if (musicResponsiveListItemRenderer != null) { ResponseSingle responseSingle = new ResponseSingle(); - String SingerHead = getJsonUrl(musicResponsiveListItemRenderer.getJSONObject("thumbnail")); + String SingerHead = getJsonUrl(musicResponsiveListItemRenderer.getJSONObject("thumbnail"),true); JSONArray flexColumns = musicResponsiveListItemRenderer.getJSONArray("flexColumns"); @@ -145,7 +145,7 @@ public class JsonHelper { JSONObject musicTwoRowItemRenderer = jsonList.optJSONObject("musicTwoRowItemRenderer"); if (musicTwoRowItemRenderer != null) { ResponseCategory responseCategory = new ResponseCategory(); - String covert = getJsonUrl(musicTwoRowItemRenderer.getJSONObject("thumbnailRenderer")); + String covert = getJsonUrl(musicTwoRowItemRenderer.getJSONObject("thumbnailRenderer"),true); JSONObject title1 = musicTwoRowItemRenderer.getJSONObject("title"); String twoTitle = getJsonTitle(title1, 0); @@ -185,7 +185,10 @@ public class JsonHelper { ResponsePlayListInfo responsePlayListInfo = new ResponsePlayListInfo(); JSONObject playlistPanelVideoRenderer = contents.getJSONObject(i).getJSONObject("playlistPanelVideoRenderer"); - String jsonUrl = getJsonUrl(playlistPanelVideoRenderer); + String maxUrl = getJsonUrl(playlistPanelVideoRenderer,true); + + String smallUrl = getJsonUrl(playlistPanelVideoRenderer, false); + String songName = getJsonTitle(playlistPanelVideoRenderer.getJSONObject("title"), 0); JSONObject longBylineText = playlistPanelVideoRenderer.getJSONObject("longBylineText"); @@ -200,7 +203,8 @@ public class JsonHelper { String[] watchEndPoint = getWatchEndPoint(playlistPanelVideoRenderer); - responsePlayListInfo.setCovert(jsonUrl); + responsePlayListInfo.setCovert(maxUrl); + responsePlayListInfo.setSmallCovert(smallUrl); responsePlayListInfo.setSongTitle(songName); responsePlayListInfo.setSingerName(singerName); responsePlayListInfo.setAlbumTitle(AlbumTitle); @@ -213,7 +217,7 @@ public class JsonHelper { responsePlayListInfo.setMusicVideoType(watchEndPoint[3]); list.add(responsePlayListInfo); - CommonUtils.LogMsg("----------歌曲名字=" + songName + "---" + Arrays.toString(watchEndPoint)); + } @@ -299,8 +303,15 @@ public class JsonHelper { return strings; } - //取最大的一张图片 - private static String getJsonUrl(JSONObject jsonObject) { + + + /** + * + * @param jsonObject + * @param maxBig 是否取最大的一张图片 + * @return + */ + private static String getJsonUrl(JSONObject jsonObject,boolean maxBig) { try { boolean b = jsonObject.has("musicThumbnailRenderer"); if (b) { @@ -308,8 +319,11 @@ public class JsonHelper { } JSONArray jsonArray = jsonObject.getJSONObject("thumbnail").getJSONArray("thumbnails"); int length = jsonArray.length(); - CommonUtils.LogMsg("----------length=" + (length - 1)); - String pngUrl = jsonArray.getJSONObject(length - 1).getString("url"); + int index = 0; + if(maxBig){ + index = length - 1; + } + String pngUrl = jsonArray.getJSONObject(index).getString("url"); return pngUrl; } catch (JSONException exception) { diff --git a/app/src/main/java/com/hi/music/player/ui/activity/PlayActivity.java b/app/src/main/java/com/hi/music/player/ui/activity/PlayActivity.java index 5f05f5b..e2d6ee7 100644 --- a/app/src/main/java/com/hi/music/player/ui/activity/PlayActivity.java +++ b/app/src/main/java/com/hi/music/player/ui/activity/PlayActivity.java @@ -12,6 +12,8 @@ import androidx.annotation.Nullable; import androidx.annotation.OptIn; import androidx.core.content.ContextCompat; import androidx.lifecycle.Observer; +import androidx.media3.common.MediaItem; +import androidx.media3.common.MediaMetadata; import androidx.media3.common.Player; import androidx.media3.common.util.UnstableApi; @@ -25,9 +27,11 @@ import com.bumptech.glide.request.target.Target; import com.hi.music.player.MusicApplication; import com.hi.music.player.R; import com.hi.music.player.api.MediaControllerListener; +import com.hi.music.player.api.onImageColorListener; import com.hi.music.player.databinding.ActivityPlayBinding; import com.hi.music.player.helper.CommonUtils; import com.hi.music.player.helper.MyValue; +import com.hi.music.player.javabean.CustomerUrlInfo; import com.hi.music.player.javabean.response.ResponsePlayListInfo; import com.hi.music.player.javabean.response.ResponsePlayUrl; import com.hi.music.player.javabean.response.child.ResponseSingle; @@ -71,34 +75,41 @@ public class PlayActivity extends BaseActivity implements S Intent intent = getIntent(); responseSingle = (ResponseSingle) intent.getSerializableExtra(MyValue.KEY_PLAY_ACTIVITY_SINGER); vmPlay = getActivityScopeViewModel(VMPlay.class); + initMediaController(); vmPlay.getPlayMusicList(responseSingle); initPlayerView(); - initMediaController(); + initProgressHandler(); vmPlay.playList.observe(this, new Observer>() { @Override public void onChanged(List playList) { + if (playList == null) { + return; + } if (playList.size() > 0) { requestPlayList = true; mPlayList = playList; musicInfo = playList.get(0); - loadCovert(musicInfo.getCovert()); - loadInfo(musicInfo); + } } }); - vmPlay.playUrlLiveData.observe(this, new Observer>() { + vmPlay.playUrlLiveData.observe(this, new Observer() { @Override - public void onChanged(Pair responsePlayUrlIntegerPair) { + public void onChanged(CustomerUrlInfo customerUrlInfo) { + if (customerUrlInfo.isNeedPlayNow() && customerUrlInfo.getPlayUrl() == null) { + // TODO: 2024/9/26 需要马上播放这首歌曲,但是此次网络请求失败 + CommonUtils.LogMsg("-------------需要马上播放这首歌曲,但是此次网络请求失败"); + return; + } requestPlayUrl = true; - mCurPlayInfo = responsePlayUrlIntegerPair.first; - Integer second = responsePlayUrlIntegerPair.second; - CommonUtils.LogMsg("---------mCurPlayInfo=" + mCurPlayInfo.getAudioUrlLow()); - updateAudioUrl(responsePlayUrlIntegerPair.first); - if (second == 0) { + mCurPlayInfo = customerUrlInfo.getPlayUrl(); + int second = customerUrlInfo.getPlayMusicIndex(); + boolean needPlayNow = customerUrlInfo.isNeedPlayNow(); + if (needPlayNow) { mediaControllerManager.play(); } } @@ -115,40 +126,65 @@ public class PlayActivity extends BaseActivity implements S private void initMediaController() { mediaControllerManager = MyMediaControllerManager.getInstance(); + mediaControllerManager.resetPlayList(); mediaControllerManager.addListener(new MediaControllerListener() { @Override public void onPlayStatus(int playStatus) { - CommonUtils.LogMsg("-------------playStatus=" + playStatus); + switch (playStatus) { case Player.STATE_IDLE: - + CommonUtils.LogMsg("-------------playStatus=STATE_IDLE"); break; case Player.STATE_BUFFERING: //快进没有缓冲的时候触发 + vb.btnPlay.setSelected(false); vb.progressBarLoading.setVisibility(View.VISIBLE); - CommonUtils.LogMsg("-------------duration STATE_BUFFERING="); + CommonUtils.LogMsg("-------------playStatus=STATE_BUFFERING"); break; case Player.STATE_READY: + vb.btnPlay.setSelected(true); mHandler.post(mRunnable); vb.progressBarLoading.setVisibility(View.GONE); - + CommonUtils.LogMsg("-------------playStatus=STATE_READY"); break; case Player.STATE_ENDED: + vb.btnPlay.setSelected(false); + CommonUtils.LogMsg("-------------playStatus=STATE_ENDED 播放完成"); mHandler.removeCallbacks(mRunnable); // 停止更新 updatePlayComplete(); + mediaControllerManager.playNext(); break; } } + + @Override + public void onRequestNextUri(String videoId, int playListIndex, boolean playNow) { + CommonUtils.LogMsg("------------onRequestNextUri= videoId=" + videoId); + if (playNow) { + vb.progressBarLoading.setVisibility(View.VISIBLE); + } + vmPlay.getPlayUrl(videoId, playListIndex, playNow); + } + + + @Override + public void onChangeMusic(MediaItem mediaItem) { + loadInfo(mediaItem); + } + }); } @Override protected void onInitClick() { - vb.btnPlay.setOnClickListener(this::onClick); + vb.btnPlay.setOnClickListener(this); vb.playProgress.setOnSeekBarChangeListener(this); + vb.btnNext.setOnClickListener(this); + vb.btnPrevious.setOnClickListener(this); + vb.imBack.setOnClickListener(this); } @@ -163,7 +199,7 @@ public class PlayActivity extends BaseActivity implements S String s = CommonUtils.convertMillisToTime(contentPos); - CommonUtils.LogMsg("---------播放进度-----contentPos=" + contentPos + "-----缓冲进度=" + bufferPos); +// CommonUtils.LogMsg("---------播放进度-----contentPos=" + contentPos + "-----缓冲进度=" + bufferPos); vb.tvCurrent.setText(s); vb.playProgress.setProgress((int) contentPos); vb.progressBarBuffer.setProgress((int) bufferPos); @@ -179,34 +215,38 @@ public class PlayActivity extends BaseActivity implements S /** - * 初始化当前播放歌曲信息 - * - * @param data + * 加载当前播放歌曲信息 */ - private void loadInfo(ResponsePlayListInfo data) { - vb.tvSongName.setText(data.getSongTitle()); - vb.tvSingerName.setText(data.getSingerName()); - vb.tvDuration.setText(data.getDuration()); + @OptIn(markerClass = UnstableApi.class) + private void loadInfo(MediaItem mediaItem) { + + MediaMetadata mediaMetadata = mediaItem.mediaMetadata; + CommonUtils.LogMsg("--------------加载当前播放歌曲信息 "+mediaMetadata.description); + if (mediaMetadata.artworkUri != null) { + loadCovert(mediaMetadata.artworkUri.toString()); + } + vb.tvSongName.setText(mediaMetadata.title); + vb.tvSingerName.setText(mediaMetadata.artist); + vb.tvDuration.setText(mediaMetadata.description); + + if (mediaMetadata.durationMs != null) { + long durationMs = mediaMetadata.durationMs; + vb.playProgress.setMax((int) durationMs); + vb.progressBarBuffer.setMax((int) durationMs); + } - long durationMs = data.getDurationMs(); - vb.playProgress.setMax((int) durationMs); - vb.progressBarBuffer.setMax((int) data.getDurationMs()); - - CommonUtils.LogMsg("--------------data.getDurationMs() 22222222222=" + durationMs); } - /** * 更新音频url到播放列表 */ private void updateAudioUrl(ResponsePlayUrl playUrl) { - mediaControllerManager.UpdateAudioUrl(playUrl); +// mediaControllerManager.UpdateAudioUrl(playUrl); } - private void loadCovert(String url) { Glide.with(MusicApplication.myApplication) .asDrawable() @@ -223,12 +263,20 @@ public class PlayActivity extends BaseActivity implements S @OptIn(markerClass = UnstableApi.class) @Override public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) { - vb.playerView.setDefaultArtwork(resource); + CommonUtils.extractDominantColor(resource, new onImageColorListener() { + @Override + public void onImageColor(int color) { + vb.rootLayout.setBackgroundColor(color); + + } + }); return false; } }) .into(vb.imCovert); + + } @@ -245,7 +293,7 @@ public class PlayActivity extends BaseActivity implements S @Override public boolean isFullScreen() { - return false; + return true; } @Override @@ -262,6 +310,13 @@ public class PlayActivity extends BaseActivity implements S } else { mediaControllerManager.pause(); } + } else if (v.equals(vb.btnNext)) { + mediaControllerManager.playNext(); + + } else if (v.equals(vb.btnPrevious)) { + mediaControllerManager.playPrevious(); + } else if (v.equals(vb.imBack)) { + finish(); } } @@ -277,7 +332,6 @@ public class PlayActivity extends BaseActivity implements S @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { - CommonUtils.LogMsg("---------onProgressChanged----progress=" + progress); mediaControllerManager.getMediaController().seekTo(progress); } } diff --git a/app/src/main/java/com/hi/music/player/ui/activity/viewmodel/VMPlay.java b/app/src/main/java/com/hi/music/player/ui/activity/viewmodel/VMPlay.java index 94d358e..9166dd3 100644 --- a/app/src/main/java/com/hi/music/player/ui/activity/viewmodel/VMPlay.java +++ b/app/src/main/java/com/hi/music/player/ui/activity/viewmodel/VMPlay.java @@ -8,6 +8,7 @@ import androidx.lifecycle.ViewModel; import com.hi.music.player.api.RequestListener; import com.hi.music.player.helper.CommonUtils; +import com.hi.music.player.javabean.CustomerUrlInfo; import com.hi.music.player.javabean.response.ResponsePlayListInfo; import com.hi.music.player.javabean.response.ResponsePlayUrl; import com.hi.music.player.javabean.response.child.ResponseSingle; @@ -28,10 +29,10 @@ public class VMPlay extends ViewModel { public LiveData> playList = _playList; - private MutableLiveData> _playUrlMutableLiveData = new MutableLiveData>(); - public LiveData> playUrlLiveData = _playUrlMutableLiveData; + private MutableLiveData _playUrlMutableLiveData = new MutableLiveData(); + public LiveData playUrlLiveData = _playUrlMutableLiveData; + - private String continuation, clickTrackingParams, visitorData; public void getPlayMusicList(ResponseSingle responseSingle) { String playlistId = responseSingle.getPlaylistId(); @@ -51,9 +52,9 @@ public class VMPlay extends ViewModel { JSONObject jsonObject = CommonUtils.toJsonObject(data); if (jsonObject != null) { List responsePlayListInfos = JsonHelper.ResolvePlayListJson(jsonObject); - MyMediaControllerManager.getInstance().addMusicPlayList(responsePlayListInfos); + MyMediaControllerManager.getInstance().setPlayList(responsePlayListInfos); _playList.setValue(responsePlayListInfos); - getPlayUrl(responseSingle,0); + getPlayUrl(responseSingle.getVideoId(),0,true); } else { _playList.setValue(null); } @@ -62,13 +63,14 @@ public class VMPlay extends ViewModel { }); } - public void getPlayUrl(ResponseSingle responseSingle, int playListIndex) { - String videoId = responseSingle.getVideoId(); + public void getPlayUrl(String videoId, int playListIndex,boolean playNow) { + CustomerUrlInfo customerUrlInfo = new CustomerUrlInfo(); + customerUrlInfo.setNeedPlayNow(playNow); RetrofitManager.getInstance().getPlayUrl(videoId, new RequestListener() { @Override public void onFail(String errorMsg) { - _playUrlMutableLiveData.setValue(null); + _playUrlMutableLiveData.setValue(customerUrlInfo); } @Override @@ -76,10 +78,12 @@ public class VMPlay extends ViewModel { JSONObject jsonObject = CommonUtils.toJsonObject(data); if (jsonObject != null) { ResponsePlayUrl responsePlayUrl = JsonHelper.ResolvePlayUrlJson(jsonObject); - _playUrlMutableLiveData.setValue(new Pair<>(responsePlayUrl, playListIndex)); - } else { - _playUrlMutableLiveData.setValue(null); + MyMediaControllerManager.getInstance().addMusicToPlayList(responsePlayUrl,playListIndex); + customerUrlInfo.setPlayUrl(responsePlayUrl); + customerUrlInfo.setPlayMusicIndex(playListIndex); + } + _playUrlMutableLiveData.setValue(customerUrlInfo); } }); diff --git a/app/src/main/res/layout/activity_play.xml b/app/src/main/res/layout/activity_play.xml index 6141761..702f45e 100644 --- a/app/src/main/res/layout/activity_play.xml +++ b/app/src/main/res/layout/activity_play.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/black" + android:id="@+id/root_layout" tools:context=".ui.activity.PlayActivity"> @@ -189,10 +189,11 @@ android:id="@+id/btn_music_list" android:layout_width="24dp" android:layout_height="24dp" - android:layout_marginBottom="40dp" android:src="@mipmap/icon_list" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintLeft_toLeftOf="@id/im_covert" /> + app:layout_constraintTop_toTopOf="@id/btn_play" + app:layout_constraintBottom_toBottomOf="@id/btn_play" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintLeft_toRightOf="@id/btn_next" /> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_play_list.xml b/app/src/main/res/layout/dialog_play_list.xml new file mode 100644 index 0000000..d7fe2ec --- /dev/null +++ b/app/src/main/res/layout/dialog_play_list.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file