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