diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 30aa626..ae78c11 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,29 +1,113 @@ - - - - - - - - - - + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
\ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3d009b6..3b93537 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ @@ -14,7 +15,8 @@ android:label="@string/app_name" android:roundIcon="@mipmap/icon" android:supportsRtl="true" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" + tools:ignore="GoogleAppIndexingWarning"> @@ -24,14 +26,19 @@ + /> + android:exported="true"/> - + + + + \ No newline at end of file diff --git a/app/src/main/assets/litepal.xml b/app/src/main/assets/litepal.xml index b6ba250..f50ac56 100644 --- a/app/src/main/assets/litepal.xml +++ b/app/src/main/assets/litepal.xml @@ -1,15 +1,18 @@ - + - + - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/musicplayer/adapter/DownloadSongAdapter.java b/app/src/main/java/com/example/musicplayer/adapter/DownloadSongAdapter.java new file mode 100644 index 0000000..eee13b3 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/adapter/DownloadSongAdapter.java @@ -0,0 +1,143 @@ +package com.example.musicplayer.adapter; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.andexert.library.RippleView; +import com.example.musicplayer.R; +import com.example.musicplayer.callback.OnItemClickListener; +import com.example.musicplayer.entiy.DownloadSong; +import com.example.musicplayer.util.FileUtil; + +import java.util.List; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/18
+ *     desc   : 已下载歌曲的适配器
+ * 
+ */ + +public class DownloadSongAdapter extends RecyclerView.Adapter { + private static final String TAG = "LoveSongAdapter"; + private int footerViewType = 1; + private int itemViewType = 0; + private List mDownloadSongList; + private Context mContext; + private int mLastPosition = -1; + private OnItemClickListener onItemClickListener; + + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + } + + public DownloadSongAdapter(Context context, List loveList) { + mContext = context; + mDownloadSongList = loveList; + } + + + class ViewHolder extends RecyclerView.ViewHolder { + TextView songNameTv; + TextView singerTv; + View playLine; + RippleView item; + + public ViewHolder(View itemView) { + super(itemView); + songNameTv = itemView.findViewById(R.id.tv_title); + singerTv = itemView.findViewById(R.id.tv_artist); + playLine = itemView.findViewById(R.id.line_play); + item = itemView.findViewById(R.id.ripple); + } + } + + /** + * 底部holder + */ + static class FooterHolder extends RecyclerView.ViewHolder { + + TextView numTv; + + public FooterHolder(View itemView) { + super(itemView); + numTv = itemView.findViewById(R.id.tv_song_num); + } + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + if (viewType == itemViewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.recycler_song_search_item, parent, false); + ViewHolder viewHolder = new ViewHolder(view); + return viewHolder; + } else { + View footerView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.footer_local_songs_item, parent, false); + FooterHolder footerHolder = new FooterHolder(footerView); + return footerHolder; + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { + if (viewHolder instanceof ViewHolder) { + ViewHolder holder = (ViewHolder) viewHolder; + final DownloadSong downloadSong = mDownloadSongList.get(position); + + holder.songNameTv.setText(downloadSong.getName()); + holder.singerTv.setText(downloadSong.getSinger()); + //根据点击显示 + if (downloadSong.getSongId().equals(FileUtil.getSong().getSongId())) { + holder.playLine.setVisibility(View.VISIBLE); + mLastPosition = position; + holder.songNameTv.setTextColor(mContext.getResources() + .getColor(R.color.yellow)); + holder.singerTv.setTextColor(mContext.getResources() + .getColor(R.color.yellow)); + } else { + holder.playLine.setVisibility(View.INVISIBLE); + holder.songNameTv.setTextColor(mContext.getResources() + .getColor(R.color.white)); + holder.singerTv.setTextColor(mContext.getResources() + .getColor(R.color.white_blue)); + } + holder.item.setOnRippleCompleteListener(rippleView -> { + if (onItemClickListener != null) { + onItemClickListener.onClick(position); + } + equalPosition(position); + }); + } else { + FooterHolder footerHolder = (FooterHolder) viewHolder; + footerHolder.numTv.setText("共" + mDownloadSongList.size() + "首音乐"); + } + } + + //判断点击的是否为上一个点击的项目 + public void equalPosition(int position) { + if (position != mLastPosition) { + notifyItemChanged(mLastPosition); + mLastPosition = position; + } + notifyItemChanged(position); + } + + @Override + public int getItemCount() { + return mDownloadSongList.size() + 1; + } + + @Override + public int getItemViewType(int position) { + return position + 1 == getItemCount() ? footerViewType : itemViewType; + } +} diff --git a/app/src/main/java/com/example/musicplayer/adapter/DownloadingAdapter.java b/app/src/main/java/com/example/musicplayer/adapter/DownloadingAdapter.java new file mode 100644 index 0000000..0767ceb --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/adapter/DownloadingAdapter.java @@ -0,0 +1,116 @@ +package com.example.musicplayer.adapter; + +import android.annotation.SuppressLint; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.SeekBar; +import android.widget.TextView; + +import com.example.musicplayer.R; +import com.example.musicplayer.app.Constant; +import com.example.musicplayer.callback.OnDeleteClickListener; +import com.example.musicplayer.callback.OnItemClickListener; +import com.example.musicplayer.entiy.DownloadInfo; +import com.example.musicplayer.util.MediaUtil; + +import java.util.List; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/17
+ *     desc   : 正在下载歌曲适配器
+ * 
+ */ + +public class DownloadingAdapter extends RecyclerView.Adapter { + + + private List downloadInfoList; + + private OnItemClickListener onItemClickListener; + private OnDeleteClickListener onDeleteClickListener; + + public void setOnDeleteClickListener(OnDeleteClickListener onDeleteClickListener){ + this.onDeleteClickListener = onDeleteClickListener; + } + + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + } + + public DownloadingAdapter(List downloadInfoList) { + this.downloadInfoList = downloadInfoList; + } + + class ViewHolder extends RecyclerView.ViewHolder { + TextView songTv; + TextView sizeTv; + SeekBar seekBar; + View itemView; + ImageView cancelTv; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + this.itemView = itemView; + songTv = itemView.findViewById(R.id.songTv); + sizeTv = itemView.findViewById(R.id.sizeTv); + seekBar = itemView.findViewById(R.id.seekBar); + cancelTv = itemView.findViewById(R.id.cancelIv); + } + } + + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + View view = LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.recycler_downing_item, viewGroup, false); + ViewHolder viewHolder = new ViewHolder(view); + return viewHolder; + } + + @SuppressLint({"SetTextI18n", "ClickableViewAccessibility"}) + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) { + ViewHolder holder = (ViewHolder) viewHolder; + if (downloadInfoList.size() == 0) return; + DownloadInfo downloadInfo = downloadInfoList.get(i); + holder.songTv.setText(downloadInfo.getSongName()); + if(downloadInfo.getStatus() == Constant.DOWNLOAD_READY){//准备开始下载 + holder.sizeTv.setText("正在获取歌曲大小"); + holder.seekBar.setVisibility(View.GONE); + } else if (downloadInfo.getStatus()==Constant.DOWNLOAD_ING) {//当前歌曲正在下载 + holder.sizeTv.setText( + MediaUtil.formatSize(downloadInfo.getCurrentSize()) + "M" + + " / " + + MediaUtil.formatSize(downloadInfo.getTotalSize()) + "M"); + holder.seekBar.setVisibility(View.VISIBLE); + }else if(downloadInfo.getStatus() == Constant.DOWNLOAD_PAUSED){//暂停 + holder.sizeTv.setText("已暂停,点击继续下载"); + holder.seekBar.setVisibility(View.GONE); + }else {//当前歌曲并未下载 + holder.sizeTv.setText(downloadInfo.getSinger()); + holder.seekBar.setVisibility(View.GONE); + } + holder.seekBar.setOnTouchListener((view, motionEvent) -> true); //消费该事件,让seekBar不能拖动和点击 + holder.seekBar.setProgress(downloadInfo.getProgress()); + //点击事件 + holder.itemView.setOnClickListener(view -> { + onItemClickListener.onClick(i); + }); + //取消 + holder.cancelTv.setOnClickListener(view -> onDeleteClickListener.onClick(i)); + + + } + + @Override + public int getItemCount() { + return downloadInfoList.size(); + } +} diff --git a/app/src/main/java/com/example/musicplayer/adapter/LoveSongAdapter.java b/app/src/main/java/com/example/musicplayer/adapter/LoveSongAdapter.java index 2846720..4e7eb81 100644 --- a/app/src/main/java/com/example/musicplayer/adapter/LoveSongAdapter.java +++ b/app/src/main/java/com/example/musicplayer/adapter/LoveSongAdapter.java @@ -41,6 +41,7 @@ public class LoveSongAdapter extends RecyclerView.Adapter mFragmentList;//顶部导航栏的内容即fragment private List mTitle;//顶部导航栏的标题 - public SearchAdapter(FragmentManager fragmentManager, Listfragments, Listtitle){ + public TabAdapter(FragmentManager fragmentManager, Listfragments, Listtitle){ super(fragmentManager); mFragmentList=fragments; mTitle=title; diff --git a/app/src/main/java/com/example/musicplayer/app/Api.java b/app/src/main/java/com/example/musicplayer/app/Api.java index a36a6e2..628ff8f 100644 --- a/app/src/main/java/com/example/musicplayer/app/Api.java +++ b/app/src/main/java/com/example/musicplayer/app/Api.java @@ -1,5 +1,7 @@ package com.example.musicplayer.app; +import android.os.Environment; + /** * Created by 残渊 on 2018/10/26. */ @@ -16,7 +18,7 @@ public class Api { */ public static String STORAGE_IMG_FILE= App.getContext().getExternalFilesDir("") + "/yuanmusic/img/"; public static String STORAGE_LRC_FILE= App.getContext().getExternalFilesDir("") + "/yuanmusic/lrc/"; - public static String STORAGE_SONG_FILE= App.getContext().getExternalFilesDir("") + "/yuanmusic/song/"; + public static String STORAGE_SONG_FILE= Environment.getExternalStorageDirectory() + "/Sxmusic/download/"; //Fiddler抓包qq音乐网站后的地址 public static final String FIDDLER_BASE_QQ_URL ="https://c.y.qq.com/"; @@ -28,6 +30,7 @@ public class Api { public static final String SONG_URL="cgi-bin/musicu.fcg?format=json"; public static final String SONG_URL_DATA_LEFT="%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%22358840384%22%2C%22songmid%22%3A%5B%22"; public static final String SONG_URL_DATA_RIGHT="%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%221443481947%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A%221443481947%22%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D "; + public static final String MP4 =".mp4"; //专辑照片 public static final String ALBUM_PIC="http://y.gtimg.cn/music/photo_new/T002R180x180M000"; public static final String JPG=".jpg"; diff --git a/app/src/main/java/com/example/musicplayer/app/Constant.java b/app/src/main/java/com/example/musicplayer/app/Constant.java index 89763da..2c7b0db 100644 --- a/app/src/main/java/com/example/musicplayer/app/Constant.java +++ b/app/src/main/java/com/example/musicplayer/app/Constant.java @@ -10,11 +10,14 @@ public class Constant { public static final int OFFSET = 30; public static final int TYPE_SONG = 1; public static final int TYPE_ALBUM = 2; - public static final int TYPE_ALBUM_SONG = 3; - public static final int LIST_TYPE_LOCAL = 0; - public static final int LIST_TYPE_ONLINE = 1; - public static final int LIST_TYPE_LOVE = 2; - public static final int LIST_TYPE_HISTORY = 3; + + //播放列表 + public static final int LIST_TYPE_LOCAL = 1; //本地列表 + public static final int LIST_TYPE_ONLINE = 2; //专辑列表 + public static final int LIST_TYPE_LOVE = 3; //我的收藏列表 + public static final int LIST_TYPE_HISTORY = 4; //最近播放列表 + public static final int LIST_TYPE_DOWNLOAD = 5; //下载列表 + public static final int HISTORY_MAX_SIZE = 100; @@ -60,5 +63,20 @@ public class Constant { //Preferences public static final String SHARED_PREFERENCES_NAME = "prefs"; - public static final String PREFS_PLAY_MODE="play_mode";//播放状态 + public static final String PREFS_PLAY_MODE = "play_mode";//播放状态 + + //download + public final static int TYPE_DOWNLOADING = 0; + public final static int TYPE_DOWNLOAD_PAUSED = 1; + public final static int TYPE_DOWNLOAD_CANCELED = 2; + public final static int TYPE_DOWNLOAD_SUCCESS = 3; + public final static int TYPE_DOWNLOAD_FAILED = 4; + public final static int TYPE_DOWNLOADED = 5; + public final static int TYPE_DOWNLOAD_ADD=6; + + //正在下载歌曲列表的状态 + public final static int DOWNLOAD_PAUSED = 0; + public final static int DOWNLOAD_WAIT=1; + public final static int DOWNLOAD_ING=2; + public final static int DOWNLOAD_READY=3; } diff --git a/app/src/main/java/com/example/musicplayer/contract/ISearchContentContract.java b/app/src/main/java/com/example/musicplayer/contract/ISearchContentContract.java index 25dc4d0..9204561 100644 --- a/app/src/main/java/com/example/musicplayer/contract/ISearchContentContract.java +++ b/app/src/main/java/com/example/musicplayer/contract/ISearchContentContract.java @@ -4,6 +4,7 @@ import com.example.musicplayer.base.presenter.IPresenter; import com.example.musicplayer.base.view.BaseView; import com.example.musicplayer.entiy.Album; import com.example.musicplayer.entiy.SearchSong; +import com.example.musicplayer.entiy.Song; import java.util.ArrayList; import java.util.List; @@ -23,13 +24,13 @@ public interface ISearchContentContract { void searchAlbumSuccess(List albumList); //获取专辑成功 void searchAlbumMoreSuccess(List songListBeans); //搜索更多内容成功 void searchAlbumError(); //获取专辑失败 - void getSongUrlSuccess(String url);//成功获取歌曲url + void getSongUrlSuccess(Song song,String url);//成功获取歌曲url } interface Presenter extends IPresenter { void search(String seek,int offset); //搜索 void searchMore(String seek,int offset); //搜索更多 void searchAlbum(String seek,int offset); //搜索专辑 void searchAlbumMore(String seek,int offset);//搜索更多专辑 - void getSongUrl(String songId);//得到歌曲的播放url + void getSongUrl(Song song);//得到歌曲的播放url } } diff --git a/app/src/main/java/com/example/musicplayer/download/DownloadListener.java b/app/src/main/java/com/example/musicplayer/download/DownloadListener.java new file mode 100644 index 0000000..ec85e45 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/download/DownloadListener.java @@ -0,0 +1,20 @@ +package com.example.musicplayer.download; + +import com.example.musicplayer.entiy.DownloadInfo; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/04/08
+ *     desc   : 监听下载过程中的各种状态
+ * 
+ */ + +public interface DownloadListener { + void onProgress(DownloadInfo downloadInfo); //进度 + void onSuccess(); //成功 + void onDownloaded();//已经下载过的歌曲 + void onFailed(); //失败 + void onPaused(); //暂停 + void onCanceled(); //取消 +} diff --git a/app/src/main/java/com/example/musicplayer/download/DownloadTask.java b/app/src/main/java/com/example/musicplayer/download/DownloadTask.java new file mode 100644 index 0000000..d6dfe6d --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/download/DownloadTask.java @@ -0,0 +1,177 @@ +package com.example.musicplayer.download; + +import android.os.AsyncTask; + + +import com.example.musicplayer.app.Api; +import com.example.musicplayer.entiy.DownloadInfo; +import com.example.musicplayer.util.DownloadUtil; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import static com.example.musicplayer.app.Constant.*; + + +/** + *
+ *     author : 残渊
+ *     time   : 2019/04/08
+ *     desc   :
+ * 
+ */ + +public class DownloadTask extends AsyncTask { + + private DownloadListener mDownListener; + private boolean isCanceled = false; + private boolean isPaused = false; + private long lastProgress; + + public DownloadTask(DownloadListener downloadListener) { + mDownListener = downloadListener; + } + + @Override + protected Integer doInBackground(DownloadInfo... downloadInfos) { + InputStream is = null; + RandomAccessFile saveFile = null; + File file = null; + DownloadInfo downloadInfo = downloadInfos[0]; + try { + long downloadedLength = 0; //记录已下载的文件长度 + String downloadUrl = downloadInfo.getUrl(); + + + File downloadFile = new File(Api.STORAGE_SONG_FILE); + if (!downloadFile.exists()) { + downloadFile.mkdirs(); + } + //传过来的下载地址 + // http://ws.stream.qqmusic.qq.com/C400001DI2Jj3Jqve9.m4a?guid=358840384&vkey=2B9BF114492F203C3943D8AE38C83DD8FEEA5E628B18F7F4455CA9B5059040266D74EBD43E09627AA4419D379B6A9E1FC1E5D2104AC7BB50&uin=0&fromtag=66 + long contentLength = getContentLength(downloadUrl); //实际文件长度 + String fileName = DownloadUtil.getSaveSongFile(downloadInfo.getSinger(),downloadInfo.getSongName(),downloadInfo.getDuration(),downloadInfo.getSongId(),contentLength); + file = new File(downloadFile ,fileName); + if (file.exists()) { + downloadedLength = file.length(); + } + if (contentLength == 0) { + return TYPE_DOWNLOAD_FAILED; + } else if (contentLength == downloadedLength) { //已下载 + return TYPE_DOWNLOADED; + } + + + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + //断点下载,指定从哪个字节开始下载 + .addHeader("RANGE", "bytes=" + downloadedLength + "-") + .url(downloadUrl) + .build(); + Response response = client.newCall(request).execute(); + + if (response != null) { + is = response.body().byteStream(); + saveFile = new RandomAccessFile(file, "rw"); + saveFile.seek(downloadedLength); //跳过已下载的字节 + byte[] b = new byte[1024]; + int total = 0; + int len; + while ((len = is.read(b)) != -1) { + if (isCanceled) { + return TYPE_DOWNLOAD_CANCELED; + } else if (isPaused) { + return TYPE_DOWNLOAD_PAUSED; + } else { + total += len; + saveFile.write(b, 0, len); + int progress = (int) ((total + downloadedLength) * 100 / contentLength); + downloadInfo.setProgress(progress); + downloadInfo.setTotalSize(contentLength); + downloadInfo.setCurrentSize(total+downloadedLength); + publishProgress(downloadInfo); + } + } + response.body().close(); + return TYPE_DOWNLOAD_SUCCESS; + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (is != null) { + is.close(); + } + if (saveFile != null) { + saveFile.close(); + } + if (isCanceled && file != null) { + file.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return TYPE_DOWNLOAD_FAILED; + } + + @Override + public void onProgressUpdate(DownloadInfo... downloadInfos) { + DownloadInfo downloadInfo = downloadInfos[0]; + int progress = downloadInfo.getProgress(); + if (progress > lastProgress) { + mDownListener.onProgress(downloadInfo); + lastProgress = progress; + } + } + + @Override + protected void onPostExecute(Integer status) { + switch (status) { + case TYPE_DOWNLOAD_SUCCESS: + mDownListener.onSuccess(); + break; + case TYPE_DOWNLOAD_FAILED: + mDownListener.onFailed(); + break; + case TYPE_DOWNLOAD_PAUSED: + mDownListener.onPaused(); + break; + case TYPE_DOWNLOAD_CANCELED: + mDownListener.onCanceled(); + break; + case TYPE_DOWNLOADED: + mDownListener.onDownloaded(); + default: + break; + } + } + + public void pauseDownload() { + isPaused = true; + } + + public void cancelDownload() { + isCanceled = true; + } + + private long getContentLength(String downloadUrl) throws IOException { + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + .url(downloadUrl) + .build(); + Response response = client.newCall(request).execute(); + if (response != null && response.isSuccessful()) { + long contentLength = response.body().contentLength(); + response.body().close(); + return contentLength; + } + return 0; + } +} diff --git a/app/src/main/java/com/example/musicplayer/entiy/DownloadInfo.java b/app/src/main/java/com/example/musicplayer/entiy/DownloadInfo.java new file mode 100644 index 0000000..febe3b2 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/entiy/DownloadInfo.java @@ -0,0 +1,118 @@ +package com.example.musicplayer.entiy; + +import org.litepal.crud.LitePalSupport; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/17
+ *     desc   : 下载的信息
+ * 
+ */ + +public class DownloadInfo extends LitePalSupport { + private long id; + private String songName; + private String singer; + private String url; + private String songId; + private int progress; + private long currentSize; + private long totalSize; +// private Song song; + private long duration; + private int position;//正在下载歌曲列表中的位置 + private int status;//下载歌曲的状态 + + public String getSongName() { + return songName; + } + + public void setSongName(String songName) { + this.songName = songName; + } + + public String getSinger() { + return singer; + } + + public void setSinger(String singer) { + this.singer = singer; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getSongId() { + return songId; + } + + public void setSongId(String songId) { + this.songId = songId; + } + + public int getProgress() { + return progress; + } + + public void setProgress(int progress) { + this.progress = progress; + } + + public long getCurrentSize() { + return currentSize; + } + + public void setCurrentSize(long currentSize) { + this.currentSize = currentSize; + } + + public long getTotalSize() { + return totalSize; + } + + public void setTotalSize(long totalSize) { + this.totalSize = totalSize; + } + +// public Song getSong() { +// return song; +// } +// +// public void setSong(Song song) { +// this.song = song; +// } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public long getId() { + return id; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } +} diff --git a/app/src/main/java/com/example/musicplayer/entiy/DownloadSong.java b/app/src/main/java/com/example/musicplayer/entiy/DownloadSong.java new file mode 100644 index 0000000..f1e8061 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/entiy/DownloadSong.java @@ -0,0 +1,87 @@ +package com.example.musicplayer.entiy; + +import org.litepal.crud.LitePalSupport; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/18
+ *     desc   : 下载的歌曲
+ * 
+ */ + +public class DownloadSong extends LitePalSupport { + private int id; + private String songId ; + private String mediaId; //下载标识符 + private String name; + private String singer; + private String url; + private String pic; + private long duration; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSinger() { + return singer; + } + + public void setSinger(String singer) { + this.singer = singer; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getPic() { + return pic; + } + + public void setPic(String pic) { + this.pic = pic; + } + + + public void setDuration(long duration) { + this.duration = duration; + } + + public long getDuration() { + return duration; + } + + public void setSongId(String songId) { + this.songId = songId; + } + + public String getSongId() { + return songId; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } +} diff --git a/app/src/main/java/com/example/musicplayer/entiy/HistorySong.java b/app/src/main/java/com/example/musicplayer/entiy/HistorySong.java index a3db2d9..952e4d5 100644 --- a/app/src/main/java/com/example/musicplayer/entiy/HistorySong.java +++ b/app/src/main/java/com/example/musicplayer/entiy/HistorySong.java @@ -9,6 +9,7 @@ import org.litepal.crud.LitePalSupport; public class HistorySong extends LitePalSupport { private int id; private String songId; + private String mediaId; //下载标识符 private String qqId; private String name; private String singer; @@ -16,6 +17,7 @@ public class HistorySong extends LitePalSupport { private String pic; private long duration; private boolean isOnline; + private boolean isDownload; @@ -91,4 +93,20 @@ public class HistorySong extends LitePalSupport { public void setQqId(String qqId) { this.qqId = qqId; } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public void setDownload(boolean download) { + isDownload = download; + } + + public boolean isDownload() { + return isDownload; + } } diff --git a/app/src/main/java/com/example/musicplayer/entiy/Love.java b/app/src/main/java/com/example/musicplayer/entiy/Love.java index 9875493..5e4614a 100644 --- a/app/src/main/java/com/example/musicplayer/entiy/Love.java +++ b/app/src/main/java/com/example/musicplayer/entiy/Love.java @@ -9,6 +9,7 @@ import org.litepal.crud.LitePalSupport; public class Love extends LitePalSupport{ private int id; private String songId; + private String mediaId; //下载标识符 private String qqId; private String name; private String singer; @@ -16,6 +17,7 @@ public class Love extends LitePalSupport{ private String pic; private long duration; private boolean isOnline; + private boolean isDownload; public int getId() { @@ -90,4 +92,20 @@ public class Love extends LitePalSupport{ public String getQqId() { return qqId; } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public boolean isDownload() { + return isDownload; + } + + public void setDownload(boolean download) { + isDownload = download; + } } diff --git a/app/src/main/java/com/example/musicplayer/entiy/OnlineSong.java b/app/src/main/java/com/example/musicplayer/entiy/OnlineSong.java index e039c0c..469f84c 100644 --- a/app/src/main/java/com/example/musicplayer/entiy/OnlineSong.java +++ b/app/src/main/java/com/example/musicplayer/entiy/OnlineSong.java @@ -9,6 +9,7 @@ import org.litepal.crud.LitePalSupport; public class OnlineSong extends LitePalSupport { private int id; private String songId; + private String mediaId; //下载标识符 private String qqId; private String name; private String singer; @@ -16,6 +17,7 @@ public class OnlineSong extends LitePalSupport { private String pic; private String lrc; private long duration; + private boolean isDownload; public int getId() { @@ -89,4 +91,20 @@ public class OnlineSong extends LitePalSupport { public void setQqId(String qqId) { this.qqId = qqId; } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public void setDownload(boolean download) { + isDownload = download; + } + + public boolean isDownload() { + return isDownload; + } } diff --git a/app/src/main/java/com/example/musicplayer/entiy/Song.java b/app/src/main/java/com/example/musicplayer/entiy/Song.java index 7d43fa5..8772749 100644 --- a/app/src/main/java/com/example/musicplayer/entiy/Song.java +++ b/app/src/main/java/com/example/musicplayer/entiy/Song.java @@ -1,80 +1,111 @@ package com.example.musicplayer.entiy; +import org.litepal.crud.LitePalSupport; + import java.io.Serializable; /** * Created by 残渊 on 2018/10/19. */ -public class Song implements Serializable { +public class Song extends LitePalSupport implements Serializable { private static final long serialVersionUID=1L; + private long id; + private String songId; //歌曲id private String qqId;//专属本地音乐,本地音乐在qq音乐中的songId + private String mediaId;//播放id,下载需要用到 private String singer; //歌手 private long duration; //总时长 private String songName; //歌曲名字 private String url; //歌曲url private long currentTime; //歌曲播放时长位置 - private int current;//在音乐列表的位置 + private int position;//在音乐列表的位置 private String imgUrl; //歌曲照片 private boolean isOnline; //是否为网络歌曲 - private int listType; //歌曲列表类别 + private int listType; //歌曲列表类别,0表示当前没有列表,即可能在播放网络歌曲 + private boolean isDownload;//是否为下载的歌曲 - public String getImgUrl() { - return imgUrl; + + public String getSongId() { + return songId; } - public int getCurrent() { - return current; + public void setSongId(String songId) { + this.songId = songId; } - public long getDuration() { - return duration; + public String getQqId() { + return qqId; } - public long getCurrentTime() { - return currentTime; + public void setQqId(String qqId) { + this.qqId = qqId; } - public String getUrl() { - return url; + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; } public String getSinger() { return singer; } + public void setSinger(String singer) { + this.singer = singer; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + public String getSongName() { return songName; } - public void setImgUrl(String imgUrl) { - this.imgUrl = imgUrl; + public void setSongName(String songName) { + this.songName = songName; } - public void setCurrent(int current) { - this.current = current; + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public long getCurrentTime() { + return currentTime; } public void setCurrentTime(long currentTime) { this.currentTime = currentTime; } - public void setDuration(long duration) { - this.duration = duration; + public int getPosition() { + return position; } - public void setUrl(String url) { - this.url = url; + public void setPosition(int position) { + this.position = position; } - public void setSinger(String singer) { - this.singer = singer; + public String getImgUrl() { + return imgUrl; } - public void setSongName(String songName) { - this.songName = songName; + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; } public boolean isOnline() { @@ -93,25 +124,21 @@ public class Song implements Serializable { this.listType = listType; } - public String getSongId() { - return songId; + public boolean isDownload() { + return isDownload; } - public void setSongId(String songId) { - this.songId = songId; - } - - public String getQqId() { - return qqId; + public void setDownload(boolean download) { + isDownload = download; } - public void setQqId(String qqId) { - this.qqId = qqId; + public long getId() { + return id; } public String toString(){ return "songName="+songName+",singer="+singer+",url="+url+",imgUrl="+imgUrl - +",duration="+duration+",currentTime="+currentTime+",current="+current + +",duration="+duration+",currentTime="+currentTime+",position="+ position +",songId="+songId+",isOnline="+isOnline+",listType="+listType; } diff --git a/app/src/main/java/com/example/musicplayer/event/DownloadEvent.java b/app/src/main/java/com/example/musicplayer/event/DownloadEvent.java new file mode 100644 index 0000000..92055c0 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/event/DownloadEvent.java @@ -0,0 +1,48 @@ +package com.example.musicplayer.event; + +import com.example.musicplayer.entiy.DownloadInfo; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/16
+ *     desc   :
+ * 
+ */ + +public class DownloadEvent { + private int downloadStatus;//下载的状态 + private DownloadInfo downloadInfo; + private int position; + + + public DownloadEvent(int status){ + downloadStatus = status; + } + public DownloadEvent(int status, DownloadInfo downloadInfo){ + downloadStatus = status; + this.downloadInfo = downloadInfo; + } + + public DownloadEvent(int status,int position){ + downloadStatus = status; + this.position = position; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + + public int getDownloadStatus() { + return downloadStatus; + } + + public DownloadInfo getDownloadInfo() { + return downloadInfo; + } +} diff --git a/app/src/main/java/com/example/musicplayer/event/SongDownloadedEvent.java b/app/src/main/java/com/example/musicplayer/event/SongDownloadedEvent.java new file mode 100644 index 0000000..727a44b --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/event/SongDownloadedEvent.java @@ -0,0 +1,12 @@ +package com.example.musicplayer.event; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/18
+ *     desc   : 已下载歌曲改变的消息
+ * 
+ */ + +public class SongDownloadedEvent { +} diff --git a/app/src/main/java/com/example/musicplayer/event/SongListNumEvent.java b/app/src/main/java/com/example/musicplayer/event/SongListNumEvent.java new file mode 100644 index 0000000..79e2ec1 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/event/SongListNumEvent.java @@ -0,0 +1,24 @@ +package com.example.musicplayer.event; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/20
+ *     desc   : 歌曲列表数量变化消息
+ * 
+ */ + +public class SongListNumEvent { + private int type; + public SongListNumEvent(int type){ + this.type = type; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/app/src/main/java/com/example/musicplayer/model/db/DbHelperImpl.java b/app/src/main/java/com/example/musicplayer/model/db/DbHelperImpl.java index b34cf0c..6ea4511 100644 --- a/app/src/main/java/com/example/musicplayer/model/db/DbHelperImpl.java +++ b/app/src/main/java/com/example/musicplayer/model/db/DbHelperImpl.java @@ -13,6 +13,7 @@ import com.example.musicplayer.entiy.Song; import org.litepal.LitePal; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -46,8 +47,8 @@ public class DbHelperImpl implements DbHelper { @Override public List getLocalMp3Info() { - List mp3InfoList = new ArrayList<>(); + getFromDownloadFile(mp3InfoList); //从下载列表中读取歌曲文件 Cursor cursor = App.getContext().getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); @@ -119,6 +120,8 @@ public class DbHelperImpl implements DbHelper { love.setSongId(song.getSongId()); love.setOnline(song.isOnline()); love.setQqId(song.getQqId()); + love.setMediaId(song.getMediaId()); + love.setDownload(song.isDownload()); return love.save(); } @@ -126,4 +129,30 @@ public class DbHelperImpl implements DbHelper { public boolean deleteFromLove(String songId) { return LitePal.deleteAll(Love.class,"songId=?",songId) !=0; } + + //从下载列表中读取文件 + private void getFromDownloadFile(List songList){ + File file = new File(Api.STORAGE_SONG_FILE); + if(!file.exists()) { + file.mkdirs(); + return; + } + + File[] subFile = file.listFiles(); + for (File value : subFile) { + String songFileName = value.getName(); + String songFile = songFileName.substring(0, songFileName.lastIndexOf(".")); + String[] songValue = songFile.split("-"); + long size = Long.valueOf(songValue[4]); + //如果文件的大小不等于实际大小,则表示该歌曲还未下载完成,被人为暂停,故跳过该歌曲,不加入到已下载集合 + if(size != value.length()) continue; + LocalSong song =new LocalSong(); + song.setSinger(songValue[0]); + song.setName(songValue[1]); + song.setDuration(Long.valueOf(songValue[2])); + song.setSongId(songValue[3]); + song.setUrl(Api.STORAGE_SONG_FILE + songFileName); + songList.add(song); + } + } } diff --git a/app/src/main/java/com/example/musicplayer/presenter/LocalPresenter.java b/app/src/main/java/com/example/musicplayer/presenter/LocalPresenter.java index 6535a02..143c89d 100644 --- a/app/src/main/java/com/example/musicplayer/presenter/LocalPresenter.java +++ b/app/src/main/java/com/example/musicplayer/presenter/LocalPresenter.java @@ -1,9 +1,11 @@ package com.example.musicplayer.presenter; +import com.example.musicplayer.app.Constant; import com.example.musicplayer.base.presenter.BasePresenter; import com.example.musicplayer.contract.ILocalContract; import com.example.musicplayer.entiy.LocalSong; +import com.example.musicplayer.event.SongListNumEvent; import com.example.musicplayer.event.SongLocalSizeChangeEvent; import org.greenrobot.eventbus.EventBus; @@ -30,7 +32,7 @@ public class LocalPresenter extends BasePresenter implement @Override public void saveSong(List localSongs) { if(mModel.saveSong(localSongs)) { - EventBus.getDefault().post(new SongLocalSizeChangeEvent()); + EventBus.getDefault().post(new SongListNumEvent(Constant.LIST_TYPE_LOCAL)); mView.showToast("成功导入本地音乐"); mView.showMusicList(localSongs); } diff --git a/app/src/main/java/com/example/musicplayer/presenter/SearchContentPresenter.java b/app/src/main/java/com/example/musicplayer/presenter/SearchContentPresenter.java index 3025c16..d4fed4e 100644 --- a/app/src/main/java/com/example/musicplayer/presenter/SearchContentPresenter.java +++ b/app/src/main/java/com/example/musicplayer/presenter/SearchContentPresenter.java @@ -7,6 +7,7 @@ import com.example.musicplayer.base.presenter.BasePresenter; import com.example.musicplayer.contract.ISearchContentContract; import com.example.musicplayer.entiy.Album; import com.example.musicplayer.entiy.SearchSong; +import com.example.musicplayer.entiy.Song; import com.example.musicplayer.entiy.SongUrl; import com.example.musicplayer.model.DataModel; import com.example.musicplayer.model.db.DbHelperImpl; @@ -116,11 +117,11 @@ public class SearchContentPresenter extends BasePresenter(mView,false,false){ @Override @@ -129,7 +130,12 @@ public class SearchContentPresenter extends BasePresenter + * author : 残渊 + * time : 2019/04/08 + * desc : 下载服务,保证DownloadTask在后台运行 + * + */ + +public class DownloadService extends Service { + private static final String TAG = "DownloadService"; + private DownloadTask downloadTask; + private String downloadUrl; + private DownloadBinder downloadBinder = new DownloadBinder(); + private LinkedList downloadQueue = new LinkedList<>();//等待队列 + private int position = 0;//下载歌曲在下载歌曲列表的位置 + private DownloadListener listener = new DownloadListener() { + @Override + public void onProgress(DownloadInfo downloadInfo) { + downloadInfo.setStatus(Constant.DOWNLOAD_ING); + EventBus.getDefault().post(new DownloadEvent(TYPE_DOWNLOADING, downloadInfo)); //通知下载模块 + if(downloadInfo.getProgress()!=100){ + getNotificationManager().notify(1, getNotification("正在下载: "+downloadInfo.getSongName(), downloadInfo.getProgress())); + }else { + if(downloadQueue.isEmpty()) getNotificationManager().notify(1, getNotification("下载成功",-1)); + } + + } + + @Override + public void onSuccess() { + downloadTask = null; + DownloadInfo downloadInfo = downloadQueue.poll(); + operateDb(downloadInfo); //操作数据库 + start();//下载队列中的其它歌曲 + //下载成功通知前台服务通知关闭,并创建一个下载成功的通知 + stopForeground(true); + if(downloadQueue.isEmpty()) getNotificationManager().notify(1, getNotification("下载成功",-1)); + } + + @Override + public void onDownloaded() { + downloadTask = null; + CommonUtil.showToast(DownloadService.this, "已下载"); + } + + @Override + public void onFailed() { + downloadTask = null; + + //下载失败通知前台服务通知关闭,并创建一个下载失败的通知 + stopForeground(true); + getNotificationManager().notify(1, getNotification("下载失败",-1)); + Toast.makeText(DownloadService.this, "下载失败", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onPaused() { + downloadTask = null; + DownloadInfo downloadInfo=downloadQueue.poll();//从下载列表中移除该歌曲 + updateDbOfPause(downloadInfo.getSongId()); + getNotificationManager().notify(1, getNotification("下载已暂停:"+downloadInfo.getSongName(), -1)); + start();//下载下载列表中的歌曲 + downloadInfo.setStatus(Constant.DOWNLOAD_PAUSED); + EventBus.getDefault().post(new DownloadEvent(Constant.TYPE_DOWNLOAD_PAUSED, downloadInfo)); //下载暂停 + Toast.makeText(DownloadService.this, "下载已暂停", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onCanceled() { + downloadTask = null; + stopForeground(true); + Toast.makeText(DownloadService.this, "下载已取消", Toast.LENGTH_SHORT).show(); + } + }; + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return downloadBinder; + } + + public class DownloadBinder extends Binder { + public void startDownload(DownloadInfo song) { + try { + postDownloadEvent(song);//通知正在下载界面 + } catch (Exception e) { + e.printStackTrace(); + } + if (downloadTask != null) { + CommonUtil.showToast(DownloadService.this, "已经加入下载队列"); + } else { + CommonUtil.showToast(DownloadService.this, "开始下载"); + start(); + } + } + + public void pauseDownload(String songId) { + //暂停的歌曲是否为当前下载的歌曲 + if (downloadTask != null &&downloadQueue.peek().getSongId().equals(songId)) { + downloadTask.pauseDownload(); + }else {//暂停的歌曲是下载队列的歌曲 + //将该歌曲从下载队列中移除 + for (int i = 0; i < downloadQueue.size(); i++) { + DownloadInfo downloadInfo = downloadQueue.get(i); + if (downloadInfo.getSongId().equals(songId)) { + downloadQueue.remove(i); + updateDbOfPause(downloadInfo.getSongId()); + downloadInfo.setStatus(Constant.DOWNLOAD_PAUSED); + EventBus.getDefault().post(new DownloadEvent(Constant.TYPE_DOWNLOAD_PAUSED, downloadInfo)); //下载暂停 + } + } + } + } + + + public void cancelDownload(DownloadInfo song) { + String songId = song.getSongId(); + //如果该歌曲正在下载,则需要将downloadTask置为null + if (downloadTask != null && downloadQueue.peek().getSongId().equals(songId)) { + downloadTask.cancelDownload(); + } + //将该歌曲从下载队列中移除 + for (int i = 0; i < downloadQueue.size(); i++) { + DownloadInfo downloadInfo = downloadQueue.get(i); + if (downloadInfo.getSongId().equals(songId)) downloadQueue.remove(i); + } + updateDb(songId); + deleteDb(songId); + //取消下载需要将文件删除并将通知关闭 + if (song.getUrl() != null) { + checkoutFile(song,song.getUrl()); //实际文件长度 + } + //通知正在下载列表 + EventBus.getDefault().post(new DownloadEvent(Constant.TYPE_DOWNLOAD_CANCELED)); + + } + + } + private void start() { + if (downloadTask == null && !downloadQueue.isEmpty()) { + DownloadInfo downloadInfo = downloadQueue.peek(); + List songList = + LitePal.where("songId = ?",downloadInfo.getSongId()).find(DownloadInfo.class); + DownloadInfo currentDownloadInfo = songList.get(0); + currentDownloadInfo.setStatus(Constant.DOWNLOAD_READY); + EventBus.getDefault().post(new DownloadEvent(TYPE_DOWNLOADING,currentDownloadInfo)); + downloadUrl = currentDownloadInfo.getUrl(); + downloadTask = new DownloadTask(listener); + downloadTask.execute(currentDownloadInfo); + getNotificationManager().notify(1, getNotification("正在下载:"+downloadInfo.getSongName(), 0)); + } + } + + + private NotificationManager getNotificationManager() { + return (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + } + + private Notification getNotification(String title,int progress) { + Intent intent = new Intent(this, MainActivity.class); + PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + String id = "channel_001"; + String name = "下载通知"; + NotificationChannel mChannel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW); + getNotificationManager().createNotificationChannel(mChannel); + Notification.Builder builder = new Notification.Builder(this, id); + builder.setSmallIcon(R.mipmap.icon); + builder.setContentIntent(pi); + builder.setContentTitle(title); + if(progress>0){ + builder.setContentText(progress +"%"); + builder.setProgress(100, progress, false); + } + return builder.build(); + } else { + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "default"); + builder.setSmallIcon(R.mipmap.icon); + builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.icon)); + builder.setContentIntent(pi); + builder.setContentTitle(title); + if(progress>0){ + builder.setContentText(progress +"%"); + builder.setProgress(100, progress, false); + } + return builder.build(); + } + } + + private void operateDb(DownloadInfo downloadInfo) { + updateDb(downloadInfo.getSongId()); + deleteDb(downloadInfo.getSongId()); + EventBus.getDefault().post(new DownloadEvent(Constant.TYPE_DOWNLOAD_SUCCESS));//通知已下载列表 + EventBus.getDefault().post(new SongListNumEvent(Constant.LIST_TYPE_DOWNLOAD)); //通知主界面的下载个数需要改变 + } + + //更新数据库中歌曲列表的位置,即下载完成歌曲后的位置都要减去1; + private void updateDb(String songId) { + long id = LitePal.select("id").where("songId = ?", songId).find(DownloadInfo.class).get(0).getId(); + List songIdList = LitePal.where("id > ?", id + "").find(DownloadInfo.class); + for (DownloadInfo song : songIdList) { + song.setPosition(song.getPosition() - 1); + song.save(); + } + } + + //暂停时更新列表歌曲状态 + private void updateDbOfPause(String songId){ + List statusList = + LitePal.where("songId = ?",songId).find(DownloadInfo.class,true); + DownloadInfo downloadInfo = statusList.get(0); + downloadInfo.setStatus(Constant.DOWNLOAD_PAUSED); + downloadInfo.save(); + } + + //下载完成时要删除下载歌曲表中的数据以及关联表中的数据 + private void deleteDb(String songId) { + LitePal.deleteAll(DownloadInfo.class, "songId=?", songId);//删除已下载歌曲的相关列 + } + + private void postDownloadEvent(DownloadInfo downloadInfo) { + //如果需要下载的表中有该条歌曲,则添加到下载队列后跳过 + List downloadInfoList = + LitePal.where("songId = ?",downloadInfo.getSongId()).find(DownloadInfo.class,true); + if (downloadInfoList.size() != 0){ + DownloadInfo historyDownloadInfo = downloadInfoList.get(0); + historyDownloadInfo.setStatus(Constant.DOWNLOAD_WAIT); + historyDownloadInfo.save(); + EventBus.getDefault().post(new DownloadEvent(Constant.DOWNLOAD_PAUSED,historyDownloadInfo)); + downloadQueue.offer(historyDownloadInfo); + return; + } + + position = LitePal.findAll(DownloadInfo.class).size(); + downloadInfo.setPosition(position); + downloadInfo.setStatus(Constant.DOWNLOAD_WAIT); //等待 + downloadInfo.save(); + downloadQueue.offer(downloadInfo);//将歌曲放到等待队列中 + EventBus.getDefault().post(new DownloadEvent(Constant.TYPE_DOWNLOAD_ADD)); + } + + + //获取歌曲实际大小,然后判断是否存在于文件中 + public void checkoutFile(DownloadInfo song, String downloadUrl){ + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + .url(downloadUrl) + .build(); + Call call= client.newCall(request); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + if(response.isSuccessful()){ + long size = response.body().contentLength(); + String fileName = DownloadUtil.getSaveSongFile(song.getSinger(),song.getSongName(),song.getDuration(),song.getSongId(),size); + File downloadFile = new File(Api.STORAGE_SONG_FILE); + String directory = String.valueOf(downloadFile); + File file = new File(fileName, directory); + if (file.exists()) { + file.delete(); + } + getNotificationManager().cancel(1); + stopForeground(true); + } + } + }); + } + +} diff --git a/app/src/main/java/com/example/musicplayer/service/PlayerService.java b/app/src/main/java/com/example/musicplayer/service/PlayerService.java index e4d2e13..de8304b 100644 --- a/app/src/main/java/com/example/musicplayer/service/PlayerService.java +++ b/app/src/main/java/com/example/musicplayer/service/PlayerService.java @@ -10,6 +10,7 @@ import android.util.Log; import com.example.musicplayer.app.Api; import com.example.musicplayer.app.Constant; +import com.example.musicplayer.entiy.DownloadSong; import com.example.musicplayer.entiy.HistorySong; import com.example.musicplayer.entiy.LocalSong; import com.example.musicplayer.entiy.Love; @@ -20,10 +21,14 @@ import com.example.musicplayer.event.OnlineSongChangeEvent; import com.example.musicplayer.event.OnlineSongErrorEvent; import com.example.musicplayer.event.SongAlbumEvent; import com.example.musicplayer.event.SongCollectionEvent; +import com.example.musicplayer.event.SongDownloadedEvent; import com.example.musicplayer.event.SongHistoryEvent; +import com.example.musicplayer.event.SongListNumEvent; import com.example.musicplayer.event.SongLocalEvent; import com.example.musicplayer.event.SongStatusEvent; import com.example.musicplayer.model.https.RetrofitFactory; +import com.example.musicplayer.util.CommonUtil; +import com.example.musicplayer.util.DownloadUtil; import com.example.musicplayer.util.FileUtil; import org.greenrobot.eventbus.EventBus; @@ -52,6 +57,7 @@ public class PlayerService extends Service { private List mSongList; private List mLoveList; private List mHistoryList; + private List mDownloadList; private int mCurrent; private int mListType; private int mPlayMode = Constant.PLAY_ORDER; //播放模式,默认为顺序播放 @@ -59,6 +65,7 @@ public class PlayerService extends Service { @Override public void onCreate() { + Log.d(TAG, "onCreate: true"); mListType = FileUtil.getSong().getListType(); if (mListType == Constant.LIST_TYPE_ONLINE) { mSongList = LitePal.findAll(OnlineSong.class); @@ -70,8 +77,10 @@ public class PlayerService extends Service { mHistoryList = orderHistoryList(LitePal.findAll(HistorySong.class)); //保证最近播放列表一开始总是第一个 Song song = FileUtil.getSong(); - song.setCurrent(0); + song.setPosition(0); FileUtil.saveSong(song); + }else if(mListType == Constant.LIST_TYPE_DOWNLOAD){ + mDownloadList = orderDownloadList(DownloadUtil.getSongFromFile(Api.STORAGE_SONG_FILE)); } } @@ -79,24 +88,28 @@ public class PlayerService extends Service { public IBinder onBind(Intent arg0) { mediaPlayer.setOnCompletionListener(mp -> { EventBus.getDefault().post(new SongStatusEvent(Constant.SONG_PAUSE));//暂停广播 - mCurrent = FileUtil.getSong().getCurrent(); + mCurrent = FileUtil.getSong().getPosition(); //将歌曲的信息保存起来 if (mListType == Constant.LIST_TYPE_LOCAL) { mCurrent=getNextCurrent(mCurrent, mPlayMode, mLocalSongList.size()); //根据播放模式来播放下一曲 saveLocalSongInfo(mCurrent); - mPlayStatusBinder.play(Constant.LIST_TYPE_LOCAL); } else if (mListType == Constant.LIST_TYPE_ONLINE) { mCurrent=getNextCurrent(mCurrent, mPlayMode, mSongList.size());//根据播放模式来播放下一曲 saveOnlineSongInfo(mCurrent); - mPlayStatusBinder.play(Constant.LIST_TYPE_ONLINE); } else if (mListType == Constant.LIST_TYPE_LOVE) { mCurrent=getNextCurrent(mCurrent, mPlayMode, mLoveList.size());//根据播放模式来播放下一曲 saveLoveInfo(mCurrent); - mPlayStatusBinder.play(Constant.LIST_TYPE_LOVE); - } else { + } else if(mListType == Constant.LIST_TYPE_HISTORY){ mCurrent=getNextCurrent(mCurrent, mPlayMode, mHistoryList.size());//根据播放模式来播放下一曲 saveHistoryInfo(mCurrent); - mPlayStatusBinder.play(Constant.LIST_TYPE_HISTORY); + }else if(mListType == Constant.LIST_TYPE_DOWNLOAD){ + mCurrent=getNextCurrent(mCurrent, mPlayMode, mDownloadList.size());//根据播放模式来播放下一曲 + saveDownloadInfo(mCurrent); + } + if(mListType!=0) { + mPlayStatusBinder.play(mListType); + }else { + mPlayStatusBinder.stop(); } }); /** @@ -119,7 +132,7 @@ public class PlayerService extends Service { mHistoryList = orderHistoryList(LitePal.findAll(HistorySong.class)); //保证最近播放列表一开始总是第一个 Song song = FileUtil.getSong(); - song.setCurrent(0); + song.setPosition(0); FileUtil.saveSong(song); } @@ -143,8 +156,11 @@ public class PlayerService extends Service { EventBus.getDefault().post(new SongCollectionEvent(true));//发送歌曲改变事件 } else if (mListType == Constant.LIST_TYPE_HISTORY) { EventBus.getDefault().post(new SongHistoryEvent()); //发送随机歌曲改变事件 + }else if(mListType == Constant.LIST_TYPE_DOWNLOAD){ + mDownloadList =orderDownloadList(DownloadUtil.getSongFromFile(Api.STORAGE_SONG_FILE)); + EventBus.getDefault().post(new SongDownloadedEvent()); //发送下载歌曲改变的消息 } - mCurrent = FileUtil.getSong().getCurrent(); + mCurrent = FileUtil.getSong().getPosition(); mediaPlayer.reset();//把各项参数恢复到初始状态 if (mListType == Constant.LIST_TYPE_LOCAL) { mediaPlayer.setDataSource(mLocalSongList.get(mCurrent).getUrl()); @@ -154,9 +170,13 @@ public class PlayerService extends Service { } else if (mListType == Constant.LIST_TYPE_LOVE) { mediaPlayer.setDataSource(mLoveList.get(mCurrent).getUrl()); startPlay(); - } else { + } else if(mListType == Constant.LIST_TYPE_HISTORY){ mediaPlayer.setDataSource(mHistoryList.get(mCurrent).getUrl()); startPlay(); + }else if(mListType == Constant.LIST_TYPE_DOWNLOAD){ + Log.d(TAG, "play: "+mDownloadList.get(mCurrent).getUrl()); + mediaPlayer.setDataSource(mDownloadList.get(mCurrent).getUrl()); + startPlay(); } } catch (Exception e) { e.printStackTrace(); @@ -207,46 +227,46 @@ public class PlayerService extends Service { public void next() { EventBus.getDefault().post(new SongStatusEvent(Constant.SONG_RESUME)); - mCurrent = FileUtil.getSong().getCurrent(); + mCurrent = FileUtil.getSong().getPosition(); if (mListType == Constant.LIST_TYPE_LOCAL) { mCurrent=getNextCurrent(mCurrent, mPlayMode, mLocalSongList.size()); //根据播放模式来播放下一曲 saveLocalSongInfo(mCurrent); - mPlayStatusBinder.play(Constant.LIST_TYPE_LOCAL); } else if (mListType == Constant.LIST_TYPE_ONLINE) { mCurrent=getNextCurrent(mCurrent, mPlayMode, mSongList.size());//根据播放模式来播放下一曲 saveOnlineSongInfo(mCurrent); - mPlayStatusBinder.play(Constant.LIST_TYPE_ONLINE); } else if (mListType == Constant.LIST_TYPE_LOVE) { mCurrent=getNextCurrent(mCurrent, mPlayMode, mLoveList.size());//根据播放模式来播放下一曲 saveLoveInfo(mCurrent); - mPlayStatusBinder.play(Constant.LIST_TYPE_LOVE); - } else { + } else if(mListType == Constant.LIST_TYPE_HISTORY){ mCurrent=getNextCurrent(mCurrent, mPlayMode, mHistoryList.size());//根据播放模式来播放下一曲 saveHistoryInfo(mCurrent); - mPlayStatusBinder.play(Constant.LIST_TYPE_HISTORY); + }else if(mListType == Constant.LIST_TYPE_DOWNLOAD){ + mCurrent=getNextCurrent(mCurrent, mPlayMode, mDownloadList.size());//根据播放模式来播放下一曲 + saveDownloadInfo(mCurrent); } + if(mListType!=0) mPlayStatusBinder.play(mListType); } public void last() { EventBus.getDefault().post(new SongStatusEvent(Constant.SONG_RESUME));//暂停广播 - mCurrent = FileUtil.getSong().getCurrent(); + mCurrent = FileUtil.getSong().getPosition(); if (mListType == Constant.LIST_TYPE_LOCAL) { mCurrent = getLastCurrent(mCurrent,mPlayMode,mLocalSongList.size()); saveLocalSongInfo(mCurrent); - mPlayStatusBinder.play(mListType); } else if (mListType == Constant.LIST_TYPE_ONLINE) { mCurrent = getLastCurrent(mCurrent,mPlayMode,mSongList.size()); saveOnlineSongInfo(mCurrent); - mPlayStatusBinder.play(mListType); } else if (mListType == Constant.LIST_TYPE_LOVE) { mCurrent = getLastCurrent(mCurrent,mPlayMode,mLoveList.size()); saveLoveInfo(mCurrent); - mPlayStatusBinder.play(mListType); - } else { + } else if(mListType == Constant.LIST_TYPE_HISTORY){ mCurrent = getLastCurrent(mCurrent,mPlayMode,mHistoryList.size()); saveHistoryInfo(mCurrent); - mPlayStatusBinder.play(mListType); + } else if(mListType == Constant.LIST_TYPE_DOWNLOAD){ + mCurrent = getLastCurrent(mCurrent,mPlayMode,mDownloadList.size()); + saveDownloadInfo(mCurrent); } + if(mListType!=0) mPlayStatusBinder.play(mListType); } /** @@ -303,7 +323,7 @@ public class PlayerService extends Service { mLocalSongList = LitePal.findAll(LocalSong.class); Song song = new Song(); LocalSong localSong = mLocalSongList.get(current); - song.setCurrent(current); + song.setPosition(current); song.setSongName(localSong.getName()); song.setSinger(localSong.getSinger()); song.setDuration(localSong.getDuration()); @@ -320,7 +340,7 @@ public class PlayerService extends Service { private void saveOnlineSongInfo(int current) { mSongList = LitePal.findAll(OnlineSong.class); Song song = new Song(); - song.setCurrent(current); + song.setPosition(current); song.setSongId(mSongList.get(current).getSongId()); song.setSongName(mSongList.get(current).getName()); song.setSinger(mSongList.get(current).getSinger()); @@ -329,6 +349,7 @@ public class PlayerService extends Service { song.setImgUrl(mSongList.get(current).getPic()); song.setOnline(true); song.setListType(Constant.LIST_TYPE_ONLINE); + song.setMediaId(mSongList.get(current).getMediaId()); FileUtil.saveSong(song); } @@ -337,7 +358,7 @@ public class PlayerService extends Service { mLoveList = orderList(LitePal.findAll(Love.class)); Love love = mLoveList.get(current); Song song = new Song(); - song.setCurrent(current); + song.setPosition(current); song.setSongId(love.getSongId()); song.setQqId(love.getQqId()); song.setSongName(love.getName()); @@ -347,6 +368,27 @@ public class PlayerService extends Service { song.setListType(Constant.LIST_TYPE_LOVE); song.setOnline(love.isOnline()); song.setDuration(love.getDuration()); + song.setMediaId(love.getMediaId()); + song.setDownload(love.isDownload()); + FileUtil.saveSong(song); + } + + + //保存下载列表的信息 + private void saveDownloadInfo(int current){ + DownloadSong downloadSong = mDownloadList.get(current); + Song song = new Song(); + song.setPosition(current); + song.setSongId(downloadSong.getSongId()); + song.setSongName(downloadSong.getName()); + song.setSinger(downloadSong.getSinger()); + song.setUrl(downloadSong.getUrl()); + song.setImgUrl(downloadSong.getPic()); + song.setListType(Constant.LIST_TYPE_DOWNLOAD); + song.setOnline(false); + song.setDuration(downloadSong.getDuration()); + song.setMediaId(downloadSong.getMediaId()); + song.setDownload(true); FileUtil.saveSong(song); } @@ -354,7 +396,7 @@ public class PlayerService extends Service { private void saveHistoryInfo(int current) { HistorySong historySong = mHistoryList.get(current); Song song = new Song(); - song.setCurrent(current); + song.setPosition(current); song.setSongId(historySong.getSongId()); song.setQqId(historySong.getQqId()); song.setSongName(historySong.getName()); @@ -364,6 +406,8 @@ public class PlayerService extends Service { song.setListType(Constant.LIST_TYPE_HISTORY); song.setOnline(historySong.isOnline()); song.setDuration(historySong.getDuration()); + song.setMediaId(historySong.getMediaId()); + song.setDownload(historySong.isDownload()); FileUtil.saveSong(song); } @@ -387,10 +431,14 @@ public class PlayerService extends Service { history.setPic(song.getImgUrl()); history.setOnline(song.isOnline()); history.setDuration(song.getDuration()); + history.setMediaId(song.getMediaId()); + history.setDownload(song.isDownload()); history.saveAsync().listen(new SaveCallback() { @Override public void onFinish(boolean success) { if (success) { + //告诉主界面最近播放的数目需要改变 + EventBus.getDefault().post(new SongListNumEvent(Constant.LIST_TYPE_HISTORY)); if (LitePal.findAll(HistorySong.class).size() > Constant.HISTORY_MAX_SIZE) { LitePal.delete(HistorySong.class, LitePal.findFirst(HistorySong.class).getId()); } @@ -404,7 +452,7 @@ public class PlayerService extends Service { } //对数据库进行倒叙排序 - private List orderList(List tempList) { + private List orderList(List tempList) { List loveList = new ArrayList<>(); loveList.clear(); for (int i = tempList.size() - 1; i >= 0; i--) { @@ -413,6 +461,15 @@ public class PlayerService extends Service { return loveList; } + private List orderDownloadList(List tempList) { + List downloadSongList = new ArrayList<>(); + downloadSongList.clear(); + for (int i = tempList.size() - 1; i >= 0; i--) { + downloadSongList.add(tempList.get(i)); + } + return downloadSongList; + } + private List orderHistoryList(List tempList) { List historySongList = new ArrayList<>(); historySongList.clear(); @@ -437,6 +494,10 @@ public class PlayerService extends Service { if (songUrl.getCode() == 0) { String sip = songUrl.getReq_0().getData().getSip().get(0); String purl = songUrl.getReq_0().getData().getMidurlinfo().get(0).getPurl(); + if(purl.equals("")) { + CommonUtil.showToast(PlayerService.this,"该歌曲暂时没有版权,试试搜索其它歌曲吧"); + return; + } Song song = FileUtil.getSong(); assert song != null; song.setUrl(sip + purl); @@ -454,7 +515,7 @@ public class PlayerService extends Service { @Override public void onError(Throwable throwable) { - + Log.d(TAG, "onError: "+throwable.toString()); } @Override diff --git a/app/src/main/java/com/example/musicplayer/util/DownloadUtil.java b/app/src/main/java/com/example/musicplayer/util/DownloadUtil.java new file mode 100644 index 0000000..457c486 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/util/DownloadUtil.java @@ -0,0 +1,81 @@ +package com.example.musicplayer.util; + +import android.util.Log; + +import com.example.musicplayer.app.Api; +import com.example.musicplayer.entiy.DownloadSong; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import static com.example.musicplayer.app.Api.STORAGE_SONG_FILE; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/24
+ *     desc   : 下载相关工具
+ * 
+ */ + +public class DownloadUtil { + /** + * + * @param fileName 文件跟目录 + * @return 得到已下载的歌曲 + */ + public static final List getSongFromFile(String fileName){ + //将.m4a截取掉得到singer-songName-duration-songId-size + List res = new ArrayList<>(); + File file=new File(fileName); + if(!file.exists()){ + file.mkdirs(); + return res; + } + File[] subFile = file.listFiles(); + for (File value : subFile) { + String songFileName = value.getName(); + String songFile = songFileName.substring(0, songFileName.lastIndexOf(".")); + String[] songValue = songFile.split("-"); + long size = Long.valueOf(songValue[4]); + //如果文件的大小不等于实际大小,则表示该歌曲还未下载完成,被人为暂停,故跳过该歌曲,不加入到已下载集合 + if(size != value.length()) continue; + DownloadSong downloadSong = new DownloadSong(); + downloadSong.setSinger(songValue[0]); + downloadSong.setName(songValue[1]); + downloadSong.setDuration(Long.valueOf(songValue[2])); + downloadSong.setSongId(songValue[3]); + downloadSong.setUrl(fileName + songFileName); + res.add(downloadSong); + } + return res; + } + + public static final boolean isExistOfDownloadSong(String songId){ + //将.m4a截取掉得到singer-songName-duration-songId-size + File file=new File(STORAGE_SONG_FILE); + if(!file.exists()){ + file.mkdirs(); + return false; + } + File[] subFile = file.listFiles(); + for (File value : subFile) { + String songFileName = value.getName(); + String songFile = songFileName.substring(0, songFileName.lastIndexOf(".")); + String[] songValue = songFile.split("-"); + //如果文件的大小不等于实际大小,则表示该歌曲还未下载完成,被人为暂停,故跳过该歌曲,不加入到已下载集合 + if(songValue[3].equals(songId)) { + long size = Long.valueOf(songValue[4]); + return size == value.length(); + } + } + return false; + } + + + //组装下载歌曲的文件名 + public static final String getSaveSongFile(String singer,String songName,long duration,String songId,long size){ + return singer+"-"+songName+"-"+duration+"-"+songId+"-"+size+".m4a"; + } +} diff --git a/app/src/main/java/com/example/musicplayer/util/MediaUtil.java b/app/src/main/java/com/example/musicplayer/util/MediaUtil.java index 12bc83b..70c1fd5 100644 --- a/app/src/main/java/com/example/musicplayer/util/MediaUtil.java +++ b/app/src/main/java/com/example/musicplayer/util/MediaUtil.java @@ -1,5 +1,6 @@ package com.example.musicplayer.util; +import android.annotation.SuppressLint; import android.content.ContentUris; import android.content.Context; import android.content.res.Resources; @@ -38,6 +39,12 @@ public class MediaUtil { return singer.trim(); } + @SuppressLint("DefaultLocale") + public static String formatSize(long size){ + double d = (double) size/1024/1024; + return String.format("%.1f",d); + } + } diff --git a/app/src/main/java/com/example/musicplayer/view/MainActivity.java b/app/src/main/java/com/example/musicplayer/view/MainActivity.java index fd9ae3e..51714a8 100644 --- a/app/src/main/java/com/example/musicplayer/view/MainActivity.java +++ b/app/src/main/java/com/example/musicplayer/view/MainActivity.java @@ -29,6 +29,7 @@ import com.example.musicplayer.base.activity.BaseActivity; import com.example.musicplayer.entiy.Song; import com.example.musicplayer.event.OnlineSongErrorEvent; import com.example.musicplayer.event.SongStatusEvent; +import com.example.musicplayer.service.DownloadService; import com.example.musicplayer.service.PlayerService; import com.example.musicplayer.util.CommonUtil; import com.example.musicplayer.util.FileUtil; @@ -71,6 +72,8 @@ public class MainActivity extends BaseActivity { private MediaPlayer mMediaPlayer; private Thread mSeekBarThread; private PlayerService.PlayStatusBinder mPlayStatusBinder; + private DownloadService.DownloadBinder mDownloadBinder; + private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { @@ -84,10 +87,23 @@ public class MainActivity extends BaseActivity { } }; + //绑定下载服务 + private ServiceConnection mDownloadConnection =new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + mDownloadBinder = (DownloadService.DownloadBinder) iBinder; + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + } + }; + @Override public void onDestroy() { super.onDestroy(); unbindService(connection); + unbindService(mDownloadConnection); EventBus.getDefault().unregister(this); if (mSeekBarThread != null || mSeekBarThread.isAlive()) mSeekBarThread.interrupt(); Song song = FileUtil.getSong(); @@ -109,7 +125,10 @@ public class MainActivity extends BaseActivity { LitePal.getDatabase(); //启动服务 Intent playIntent = new Intent(MainActivity.this, PlayerService.class); + Intent downIntent = new Intent(MainActivity.this,DownloadService.class); bindService(playIntent, connection, Context.BIND_AUTO_CREATE); + bindService(downIntent,mDownloadConnection,Context.BIND_AUTO_CREATE); + //设置属性动画 mCircleAnimator = ObjectAnimator.ofFloat(mCoverIv, "rotation", 0.0f, 360.0f); mCircleAnimator.setDuration(30000); diff --git a/app/src/main/java/com/example/musicplayer/view/PlayActivity.java b/app/src/main/java/com/example/musicplayer/view/PlayActivity.java index fdd0e9d..a26f87b 100644 --- a/app/src/main/java/com/example/musicplayer/view/PlayActivity.java +++ b/app/src/main/java/com/example/musicplayer/view/PlayActivity.java @@ -43,11 +43,15 @@ import com.example.musicplayer.app.Api; import com.example.musicplayer.app.Constant; import com.example.musicplayer.base.activity.BaseMvpActivity; import com.example.musicplayer.contract.IPlayContract; +import com.example.musicplayer.entiy.DownloadInfo; +import com.example.musicplayer.entiy.DownloadSong; import com.example.musicplayer.entiy.LocalSong; import com.example.musicplayer.entiy.Song; +import com.example.musicplayer.event.DownloadEvent; import com.example.musicplayer.event.SongCollectionEvent; import com.example.musicplayer.event.SongStatusEvent; import com.example.musicplayer.presenter.PlayPresenter; +import com.example.musicplayer.service.DownloadService; import com.example.musicplayer.service.PlayerService; import com.example.musicplayer.util.CommonUtil; import com.example.musicplayer.util.DisplayUtil; @@ -62,18 +66,11 @@ import com.example.musicplayer.widget.LrcView; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import org.litepal.LitePal; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.ref.WeakReference; import java.util.List; import butterknife.BindView; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; /** * 播放界面 @@ -142,7 +139,10 @@ public class PlayActivity extends BaseMvpActivity implements IPla private List mLocalSong;//用来判断是否有本地照片 //服务 private PlayerService.PlayStatusBinder mPlayStatusBinder; - private ServiceConnection connection = new ServiceConnection() { + private DownloadService.DownloadBinder mDownloadBinder; + + //播放 + private ServiceConnection mPlayConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mPlayStatusBinder = (PlayerService.PlayStatusBinder) service; @@ -179,6 +179,19 @@ public class PlayActivity extends BaseMvpActivity implements IPla } }; + //绑定下载服务 + private ServiceConnection mDownloadConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + mDownloadBinder = (DownloadService.DownloadBinder) iBinder; + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + + } + }; + @SuppressLint("HandlerLeak") private Handler mMusicHandler = new Handler() { @Override @@ -206,9 +219,11 @@ public class PlayActivity extends BaseMvpActivity implements IPla //判断播放状态 mPlayStatus = getIntent().getIntExtra(Constant.PLAYER_STATUS, 2); - //绑定服务 + //绑定服务,播放和下载的服务 Intent playIntent = new Intent(PlayActivity.this, PlayerService.class); - bindService(playIntent, connection, Context.BIND_AUTO_CREATE); + Intent downIntent = new Intent(PlayActivity.this, DownloadService.class); + bindService(playIntent, mPlayConnection, Context.BIND_AUTO_CREATE); + bindService(downIntent, mDownloadConnection, Context.BIND_AUTO_CREATE); //界面填充 mSong = FileUtil.getSong(); @@ -219,19 +234,31 @@ public class PlayActivity extends BaseMvpActivity implements IPla mSeekBar.setMax((int) mSong.getDuration()); mSeekBar.setProgress((int) mSong.getCurrentTime()); mDownLoadIv.setVisibility(mSong.isOnline() ? View.VISIBLE : View.GONE); //下载按钮是否隐藏 + mDownLoadIv.setImageDrawable(mSong.isDownload() ? getDrawable(R.drawable.downloaded) : getDrawable(R.drawable.download_song)); mPlayMode = mPresenter.getPlayMode();//得到播放模式 - if(mPlayMode == Constant.PLAY_ORDER){ + if (mPlayMode == Constant.PLAY_ORDER) { mPlayModeBtn.setBackground(getDrawable(R.drawable.play_mode_order)); - }else if(mPlayMode == Constant.PLAY_RANDOM){ + } else if (mPlayMode == Constant.PLAY_RANDOM) { mPlayModeBtn.setBackground(getDrawable(R.drawable.play_mode_random)); - }else { + } else { mPlayModeBtn.setBackground(getDrawable(R.drawable.play_mode_single)); } } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onDownloadSuccessEvent(DownloadEvent event){ + if(event.getDownloadStatus() == Constant.TYPE_DOWNLOAD_SUCCESS){ + mDownLoadIv.setImageDrawable( + LitePal.where("songId=?", mSong.getSongId()).find(DownloadSong.class).size() != 0 + ? getDrawable(R.drawable.downloaded) + : getDrawable(R.drawable.download_song)); + } + } + @Override protected PlayPresenter getPresenter() { //与Presenter建立关系 @@ -321,7 +348,7 @@ public class PlayActivity extends BaseMvpActivity implements IPla public void onStopTrackingTouch(SeekBar seekBar) { if (mPlayStatusBinder.isPlaying()) { mMediaPlayer = mPlayStatusBinder.getMediaPlayer(); - mMediaPlayer.seekTo(seekBar.getProgress()*1000); + mMediaPlayer.seekTo(seekBar.getProgress() * 1000); startUpdateSeekBarProgress(); } else { time = seekBar.getProgress(); @@ -347,8 +374,8 @@ public class PlayActivity extends BaseMvpActivity implements IPla mPlayStatusBinder.resume(); flag = false; if (isSeek) { - Log.d(TAG, "onClick: "+time); - mMediaPlayer.seekTo(time*1000); + Log.d(TAG, "onClick: " + time); + mMediaPlayer.seekTo(time * 1000); isSeek = false; } mDisc.play(); @@ -360,7 +387,7 @@ public class PlayActivity extends BaseMvpActivity implements IPla } else { mPlayStatusBinder.play(mListType); } - mMediaPlayer.seekTo((int) mSong.getCurrentTime()*1000); + mMediaPlayer.seekTo((int) mSong.getCurrentTime() * 1000); mDisc.play(); mPlayBtn.setSelected(true); startUpdateSeekBarProgress(); @@ -399,18 +426,18 @@ public class PlayActivity extends BaseMvpActivity implements IPla String lrc = FileUtil.getLrcFromNative(mSong.getSongName()); if (null == lrc) { String qqId = mSong.getQqId(); - if(Constant.SONG_ID_UNFIND.equals(qqId)){//匹配不到歌词 + if (Constant.SONG_ID_UNFIND.equals(qqId)) {//匹配不到歌词 getLrcError(null); - }else if(null == qqId){//歌曲的id还未匹配 - mPresenter.getSongId(mSong.getSongName(),mSong.getDuration()); - }else {//歌词还未匹配 - mPresenter.getLrc(qqId,Constant.SONG_LOCAL); + } else if (null == qqId) {//歌曲的id还未匹配 + mPresenter.getSongId(mSong.getSongName(), mSong.getDuration()); + } else {//歌词还未匹配 + mPresenter.getLrc(qqId, Constant.SONG_LOCAL); } - }else { + } else { showLrc(lrc); } } else { - mPresenter.getLrc(mSong.getSongId(),Constant.SONG_ONLINE); + mPresenter.getLrc(mSong.getSongId(), Constant.SONG_ONLINE); } } ); @@ -421,8 +448,11 @@ public class PlayActivity extends BaseMvpActivity implements IPla }); //歌曲下载 mDownLoadIv.setOnClickListener(v -> { - CommonUtil.showToast(this, "开始下载歌曲"); - downLoad(mSong.getUrl(), mSong.getSongName()); + if (mSong.isDownload()) { + showToast(getString(R.string.downloded)); + } else { + mDownloadBinder.startDownload(getDownloadInfoFromSong(mSong)); + } }); } @@ -628,60 +658,20 @@ public class PlayActivity extends BaseMvpActivity implements IPla @Override public void getSongIdSuccess(String songId) { - Log.d(TAG, "getSongIdSuccess: "+songId); + Log.d(TAG, "getSongIdSuccess: " + songId); setLocalSongId(songId);//保存音乐信息 - mPresenter.getLrc(songId,Constant.SONG_LOCAL);//获取歌词 + mPresenter.getLrc(songId, Constant.SONG_LOCAL);//获取歌词 } @Override public void saveLrc(String lrc) { - FileUtil.saveLrcToNative(lrc,mSong.getSongName()); - } - - private void downLoad(String url, String song) { - new Thread(() -> { - File file = new File(Api.STORAGE_SONG_FILE); - if (!file.exists()) { - file.mkdirs(); - } - File songFile = new File(file, song + ".mp3"); - BufferedOutputStream out = null; - try { - OkHttpClient client = new OkHttpClient(); - Request request = new Request.Builder().url(url).build(); - Response response = client.newCall(request).execute(); - if (response.isSuccessful()) { - out = new BufferedOutputStream(new FileOutputStream(songFile)); - byte[] bytes = response.body().bytes(); - out.write(bytes, 0, bytes.length); - out.close(); - } - showLoadSuccess(); - } catch (IOException e) { - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (out != null) out.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }).start(); + FileUtil.saveLrcToNative(lrc, mSong.getSongName()); } - private void showLoadSuccess() { - runOnUiThread(() -> { - CommonUtil.showToast(this, "歌曲下载成功"); - }); - - } - //改变播放模式 - private void changePlayMode(){ - View playModeView = LayoutInflater.from(this).inflate(R.layout.play_mode,null); + private void changePlayMode() { + View playModeView = LayoutInflater.from(this).inflate(R.layout.play_mode, null); ConstraintLayout orderLayout = playModeView.findViewById(R.id.orderLayout); ConstraintLayout randomLayout = playModeView.findViewById(R.id.randomLayout); ConstraintLayout singleLayout = playModeView.findViewById(R.id.singleLayout); @@ -690,7 +680,7 @@ public class PlayActivity extends BaseMvpActivity implements IPla TextView singleTv = playModeView.findViewById(R.id.singleTv); //显示弹窗 - PopupWindow popupWindow = new PopupWindow(playModeView, ScreenUtil.dip2px(this,130),ScreenUtil.dip2px(this,150)); + PopupWindow popupWindow = new PopupWindow(playModeView, ScreenUtil.dip2px(this, 130), ScreenUtil.dip2px(this, 150)); //设置背景色 popupWindow.setBackgroundDrawable(getDrawable(R.color.transparent)); //设置焦点 @@ -699,20 +689,20 @@ public class PlayActivity extends BaseMvpActivity implements IPla popupWindow.setOutsideTouchable(true); popupWindow.update(); //设置弹出的位置 - popupWindow.showAsDropDown(mPlayModeBtn,0,-50); + popupWindow.showAsDropDown(mPlayModeBtn, 0, -50); //显示播放模式 int mode = mPresenter.getPlayMode(); - if(mode == Constant.PLAY_ORDER){ + if (mode == Constant.PLAY_ORDER) { orderTv.setSelected(true); randomTv.setSelected(false); singleTv.setSelected(false); - }else if(mode == Constant.PLAY_RANDOM){ + } else if (mode == Constant.PLAY_RANDOM) { randomTv.setSelected(true); orderTv.setSelected(false); singleTv.setSelected(false); - }else { + } else { singleTv.setSelected(true); randomTv.setSelected(false); orderTv.setSelected(false); @@ -749,7 +739,8 @@ public class PlayActivity extends BaseMvpActivity implements IPla @Override public void onDestroy() { super.onDestroy(); - unbindService(connection); + unbindService(mPlayConnection); + unbindService(mDownloadConnection); EventBus.getDefault().unregister(this); stopUpdateSeekBarProgress(); @@ -757,4 +748,15 @@ public class PlayActivity extends BaseMvpActivity implements IPla mMusicHandler.removeCallbacksAndMessages(null); } + private DownloadInfo getDownloadInfoFromSong(Song song){ + DownloadInfo downloadInfo = new DownloadInfo(); + downloadInfo.setSinger(song.getSinger()); + downloadInfo.setProgress(0); + downloadInfo.setSongId(song.getSongId()); + downloadInfo.setUrl(song.getUrl()); + downloadInfo.setSongName(song.getSongName()); + downloadInfo.setDuration(song.getDuration()); + return downloadInfo; + } + } diff --git a/app/src/main/java/com/example/musicplayer/view/main/MainFragment.java b/app/src/main/java/com/example/musicplayer/view/main/MainFragment.java index cd0b8ab..7e645f5 100644 --- a/app/src/main/java/com/example/musicplayer/view/main/MainFragment.java +++ b/app/src/main/java/com/example/musicplayer/view/main/MainFragment.java @@ -5,7 +5,6 @@ import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -14,12 +13,19 @@ import android.widget.TextView; import com.example.musicplayer.R; import com.example.musicplayer.adapter.ExpandableListViewAdapter; +import com.example.musicplayer.app.Api; +import com.example.musicplayer.app.Constant; import com.example.musicplayer.entiy.AlbumCollection; import com.example.musicplayer.entiy.HistorySong; import com.example.musicplayer.entiy.LocalSong; import com.example.musicplayer.entiy.Love; import com.example.musicplayer.event.AlbumCollectionEvent; -import com.example.musicplayer.event.SongLocalSizeChangeEvent; +import com.example.musicplayer.event.SongListNumEvent; +import com.example.musicplayer.util.DownloadUtil; +import com.example.musicplayer.view.main.collection.CollectionFragment; +import com.example.musicplayer.view.main.download.DownloadFragment; +import com.example.musicplayer.view.main.history.HistoryFragment; +import com.example.musicplayer.view.main.local.LocalFragment; import com.example.musicplayer.view.search.AlbumContentFragment; import com.example.musicplayer.widget.MyListView; @@ -40,8 +46,8 @@ public class MainFragment extends Fragment { private MyListView myListView; private ExpandableListViewAdapter mAdapter; - private LinearLayout mLocalMusicLinear, mCollectionLinear, mHistoryMusicLinear; - private TextView mLocalMusicNum, mLoveMusicNum, mHistoryMusicNum; + private LinearLayout mLocalMusicLinear, mCollectionLinear, mHistoryMusicLinear,mDownloadLinear; + private TextView mLocalMusicNum, mLoveMusicNum, mHistoryMusicNum,mDownloadMusicNum; private TextView mSeekBtn; private List> mAlbumCollectionList; @@ -66,6 +72,8 @@ public class MainFragment extends Fragment { mLocalMusicNum = view.findViewById(R.id.tv_local_music_num); mLoveMusicNum = view.findViewById(R.id.tv_love_num); mHistoryMusicNum = view.findViewById(R.id.tv_history_num); + mDownloadMusicNum = view.findViewById(R.id.tv_download_num); + mDownloadLinear = view.findViewById(R.id.downloadLinear); return view; } @@ -118,23 +126,39 @@ public class MainFragment extends Fragment { } @Subscribe(threadMode = ThreadMode.MAIN) - public void onLocalSizeEvent(SongLocalSizeChangeEvent event) { - mLocalMusicNum.setText(String.valueOf(LitePal.findAll(LocalSong.class).size())); + public void onSongListEvent(SongListNumEvent event){ + int type = event.getType(); + if(type == Constant.LIST_TYPE_HISTORY){ + mHistoryMusicNum.setText(String.valueOf(LitePal.findAll(HistorySong.class).size())); + }else if(type == Constant.LIST_TYPE_LOCAL){ + mLocalMusicNum.setText(String.valueOf(LitePal.findAll(LocalSong.class).size())); + }else if(type == Constant.LIST_TYPE_DOWNLOAD){ + mDownloadMusicNum.setText(String.valueOf(DownloadUtil.getSongFromFile(Api.STORAGE_SONG_FILE).size())); + } } + + private void onClick() { + //本地音乐 mLocalMusicLinear.setOnClickListener(v -> replaceFragment(new LocalFragment())); - + //搜索 mSeekBtn.setOnClickListener(v -> replaceFragment(new AlbumContentFragment.SearchFragment())); - + //我的收藏 mCollectionLinear.setOnClickListener(v -> replaceFragment(new CollectionFragment())); - + //下载 + mDownloadLinear.setOnClickListener(view -> replaceFragment(new DownloadFragment())); + //最近播放 mHistoryMusicLinear.setOnClickListener(v -> replaceFragment(new HistoryFragment())); + + //歌单点击展开 myListView.setOnGroupExpandListener(groupPosition -> { if (groupPosition == 1) { twoExpand = true; } }); + + //歌单点击收缩 myListView.setOnGroupCollapseListener(groupPosition -> { if (groupPosition == 1) { twoExpand = false; @@ -179,6 +203,7 @@ public class MainFragment extends Fragment { mLocalMusicNum.setText(String.valueOf(LitePal.findAll(LocalSong.class).size())); mLoveMusicNum.setText(String.valueOf(LitePal.findAll(Love.class).size())); mHistoryMusicNum.setText(String.valueOf(LitePal.findAll(HistorySong.class).size())); + mDownloadMusicNum.setText(String.valueOf(DownloadUtil.getSongFromFile(Api.STORAGE_SONG_FILE).size())); } //使数据库中的列表逆序排列 diff --git a/app/src/main/java/com/example/musicplayer/view/main/CollectionFragment.java b/app/src/main/java/com/example/musicplayer/view/main/collection/CollectionFragment.java similarity index 90% rename from app/src/main/java/com/example/musicplayer/view/main/CollectionFragment.java rename to app/src/main/java/com/example/musicplayer/view/main/collection/CollectionFragment.java index f08eb03..beba7bb 100644 --- a/app/src/main/java/com/example/musicplayer/view/main/CollectionFragment.java +++ b/app/src/main/java/com/example/musicplayer/view/main/collection/CollectionFragment.java @@ -1,4 +1,4 @@ -package com.example.musicplayer.view.main; +package com.example.musicplayer.view.main.collection; import android.content.ComponentName; @@ -32,6 +32,7 @@ import org.litepal.LitePal; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Created by 残渊 on 2018/11/30. @@ -62,7 +63,7 @@ public class CollectionFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View mView = inflater.inflate(R.layout.fragment_love_music, container, false); + View mView = inflater.inflate(R.layout.fragment_love, container, false); EventBus.getDefault().register(this); //注册事件订阅者 mRecycler = mView.findViewById(R.id.recycler_love_songs); mBackIv = mView.findViewById(R.id.iv_back); @@ -75,7 +76,7 @@ public class CollectionFragment extends Fragment { super.onActivityCreated(savedInstanceState); //启动服务 Intent playIntent = new Intent(getActivity(), PlayerService.class); - getActivity().bindService(playIntent, connection, Context.BIND_AUTO_CREATE); + Objects.requireNonNull(getActivity()).bindService(playIntent, connection, Context.BIND_AUTO_CREATE); showSongList(); onClick(); } @@ -83,7 +84,7 @@ public class CollectionFragment extends Fragment { public void onDestroy(){ super.onDestroy(); EventBus.getDefault().unregister(this); - getActivity().unbindService(connection); + Objects.requireNonNull(getActivity()).unbindService(connection); } @Subscribe(threadMode = ThreadMode.MAIN ) @@ -93,7 +94,7 @@ public class CollectionFragment extends Fragment { mAdapter.notifyDataSetChanged(); if(songCollectionEvent.isLove()){//定位歌曲 if (FileUtil.getSong() != null) { - mManager.scrollToPositionWithOffset(FileUtil.getSong().getCurrent() + 4, mRecycler.getHeight()); + mManager.scrollToPositionWithOffset(FileUtil.getSong().getPosition() + 4, mRecycler.getHeight()); } } } @@ -117,8 +118,9 @@ public class CollectionFragment extends Fragment { song.setOnline(love.isOnline()); song.setUrl(love.getUrl()); song.setImgUrl(love.getPic()); - song.setCurrent(position); + song.setPosition(position); song.setDuration(love.getDuration()); + song.setMediaId(love.getMediaId()); song.setListType(Constant.LIST_TYPE_LOVE); FileUtil.saveSong(song); diff --git a/app/src/main/java/com/example/musicplayer/view/main/download/DownloadFragment.java b/app/src/main/java/com/example/musicplayer/view/main/download/DownloadFragment.java new file mode 100644 index 0000000..8abbe67 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/view/main/download/DownloadFragment.java @@ -0,0 +1,77 @@ +package com.example.musicplayer.view.main.download; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.example.musicplayer.R; +import com.example.musicplayer.adapter.TabAdapter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/16
+ *     desc   : 下载模块
+ * 
+ */ + +public class DownloadFragment extends Fragment { + @BindView(R.id.backIv) + ImageView backIv; + @BindView(R.id.tabLayout) + TabLayout tabLayout; + @BindView(R.id.page) + ViewPager page; + private Unbinder unbinder; + private List mTitleList; + private List mFragments; + private TabAdapter mAdapter; + private String[] mTitles = {"已下载", "正在下载"}; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_download, container, false); + unbinder = ButterKnife.bind(this, view); + initTab(); + onClick(); + return view; + + } + + private void initTab() { + mTitleList = new ArrayList<>(); + mFragments = new ArrayList<>(); + mTitleList.addAll(Arrays.asList(mTitles)); + mFragments.add(new DownloadMusicFragment()); + mFragments.add(new DownloadingFragment()); + mAdapter = new TabAdapter(getChildFragmentManager(), mFragments, mTitleList); + page.setAdapter(mAdapter); + tabLayout.setupWithViewPager(page); + } + private void onClick(){ + backIv.setOnClickListener(view -> Objects.requireNonNull(getActivity()).getSupportFragmentManager().popBackStack()); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } +} diff --git a/app/src/main/java/com/example/musicplayer/view/main/download/DownloadMusicFragment.java b/app/src/main/java/com/example/musicplayer/view/main/download/DownloadMusicFragment.java new file mode 100644 index 0000000..4ad56cd --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/view/main/download/DownloadMusicFragment.java @@ -0,0 +1,151 @@ +package com.example.musicplayer.view.main.download; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.example.musicplayer.R; +import com.example.musicplayer.adapter.DownloadSongAdapter; +import com.example.musicplayer.app.Constant; +import com.example.musicplayer.entiy.DownloadSong; +import com.example.musicplayer.entiy.Song; +import com.example.musicplayer.event.DownloadEvent; +import com.example.musicplayer.event.SongDownloadedEvent; +import com.example.musicplayer.service.PlayerService; +import com.example.musicplayer.util.DownloadUtil; +import com.example.musicplayer.util.FileUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; + +import static com.example.musicplayer.app.Api.STORAGE_SONG_FILE; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/16
+ *     desc   : 下载歌曲列表
+ * 
+ */ + +public class DownloadMusicFragment extends Fragment { + private static final String TAG = "DownloadMusicFragment"; + + @BindView(R.id.songRecycle) + RecyclerView songRecycle; + Unbinder unbinder; + + private LinearLayoutManager mManager; + private DownloadSongAdapter mAdapter; + private List mDownloadSongList; //已下载歌曲列表 + + private PlayerService.PlayStatusBinder mPlayStatusBinder; + private ServiceConnection connection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mPlayStatusBinder = (PlayerService.PlayStatusBinder) service; + } + + @Override + public void onServiceDisconnected(ComponentName name) { + + } + }; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_download_music, container, false); + EventBus.getDefault().register(this); + unbinder = ButterKnife.bind(this, view); + mDownloadSongList = new ArrayList<>(); + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + //启动服务 + Intent playIntent = new Intent(getActivity(), PlayerService.class); + Objects.requireNonNull(getActivity()).bindService(playIntent, connection, Context.BIND_AUTO_CREATE); + showSongList(); + } + + private void showSongList(){ + mDownloadSongList = orderList(DownloadUtil.getSongFromFile(STORAGE_SONG_FILE)); + mAdapter = new DownloadSongAdapter(getActivity(), mDownloadSongList); + mManager = new LinearLayoutManager(getActivity()); + songRecycle.setLayoutManager(mManager); + songRecycle.setAdapter(mAdapter); + + mAdapter.setOnItemClickListener(position -> { + DownloadSong downloadSong = mDownloadSongList.get(position); + Song song = new Song(); + song.setSongId(downloadSong.getSongId()); + song.setSongName(downloadSong.getName()); + song.setSinger(downloadSong.getSinger()); + song.setOnline(false); + song.setUrl(downloadSong.getUrl()); + Log.d(TAG, "showSongList: "+song.getUrl()); + song.setImgUrl(downloadSong.getPic()); + song.setPosition(position); + song.setDuration(downloadSong.getDuration()); + song.setListType(Constant.LIST_TYPE_DOWNLOAD); + song.setMediaId(downloadSong.getMediaId()); + song.setDownload(true); + FileUtil.saveSong(song); + + mPlayStatusBinder.play(Constant.LIST_TYPE_DOWNLOAD); + }); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onDownloadSuccessEvent(DownloadEvent event){ + if(event.getDownloadStatus() == Constant.TYPE_DOWNLOAD_SUCCESS){ + mDownloadSongList.clear(); + mDownloadSongList.addAll(orderList(DownloadUtil.getSongFromFile(STORAGE_SONG_FILE))); + mAdapter.notifyDataSetChanged(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onSongDownloadedEvent(SongDownloadedEvent event){ + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + EventBus.getDefault().unregister(this); + } + private List orderList(List tempList){ + List loveList=new ArrayList<>(); + loveList.clear(); + for(int i=tempList.size()-1;i>=0;i--){ + loveList.add(tempList.get(i)); + } + return loveList; + } +} diff --git a/app/src/main/java/com/example/musicplayer/view/main/download/DownloadingFragment.java b/app/src/main/java/com/example/musicplayer/view/main/download/DownloadingFragment.java new file mode 100644 index 0000000..2399cc4 --- /dev/null +++ b/app/src/main/java/com/example/musicplayer/view/main/download/DownloadingFragment.java @@ -0,0 +1,169 @@ +package com.example.musicplayer.view.main.download; + +import android.app.Dialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.example.SpeedDialog.dialog.SpeedDialog; +import com.example.SpeedDialog.listener.OnSelectClickListener; +import com.example.musicplayer.R; +import com.example.musicplayer.adapter.DownloadingAdapter; +import com.example.musicplayer.app.Constant; +import com.example.musicplayer.entiy.DownloadInfo; +import com.example.musicplayer.entiy.Song; +import com.example.musicplayer.event.DownloadEvent; +import com.example.musicplayer.service.DownloadService; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; +import org.litepal.LitePal; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; + +/** + *
+ *     author : 残渊
+ *     time   : 2019/09/16
+ *     desc   : 正在下载歌曲列表
+ * 
+ */ + +public class DownloadingFragment extends Fragment { + private static final String TAG = "DownloadingFragment"; + + @BindView(R.id.songDowningRecycle) + RecyclerView songDowningRecycle; + Unbinder unbinder; + private DownloadingAdapter mAdapter; + private LinearLayoutManager mLinearLayoutManager; + private List mDownloadInfoList; //下载队列 + + private DownloadService.DownloadBinder mDownloadBinder; + //绑定下载服务 + private ServiceConnection mDownloadConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + mDownloadBinder = (DownloadService.DownloadBinder) iBinder; + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + + } + }; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_download_ing, container, false); + EventBus.getDefault().register(this); + unbinder = ButterKnife.bind(this, view); + return view; + } + + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + initRecycler(); + //绑定服务 + Intent downIntent = new Intent(getActivity(), DownloadService.class); + getActivity().bindService(downIntent, mDownloadConnection, Context.BIND_AUTO_CREATE); + super.onActivityCreated(savedInstanceState); + } + + private void initRecycler() { + mDownloadInfoList = new LinkedList<>(); + mDownloadInfoList.addAll(LitePal.findAll(DownloadInfo.class,true)); + songDowningRecycle.setItemAnimator(null); //解决进度刷新闪屏问题 + mLinearLayoutManager = new LinearLayoutManager(getActivity()); + mAdapter = new DownloadingAdapter(mDownloadInfoList); + songDowningRecycle.setLayoutManager(mLinearLayoutManager); + songDowningRecycle.setAdapter(mAdapter); + + //暂停 + mAdapter.setOnItemClickListener(position -> { + DownloadInfo downloadInfo = mDownloadInfoList.get(position); + Log.d(TAG, "initRecycler: "+mDownloadInfoList.get(position).getStatus()); + //判断是否为正在播放的歌曲 + if(downloadInfo.getStatus() == Constant.DOWNLOAD_PAUSED){ + mDownloadBinder.startDownload(downloadInfo); + }else { + //传入要暂停的音乐id + mDownloadBinder.pauseDownload(downloadInfo.getSongId()); + } + }); + + //取消下载 + mAdapter.setOnDeleteClickListener(position -> { + SpeedDialog speedDialog = new SpeedDialog(getActivity(),SpeedDialog.SELECT_TYPE); + speedDialog.setTitle(getString(R.string.download_cancel)) + .setMessage(getString(R.string.download_cancel_message)) + .setSureText(getString(R.string.download_sure)) + .setSureClickListener(dialog -> { + mDownloadBinder.cancelDownload(mDownloadInfoList.get(position)); + }) + .show(); + }); + + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onDownloadingMessage(DownloadEvent event) { + int status = event.getDownloadStatus(); + if (status == Constant.TYPE_DOWNLOADING || status == Constant.TYPE_DOWNLOAD_PAUSED) {//进度条更新 + DownloadInfo downloadInfo = event.getDownloadInfo(); + mDownloadInfoList.remove(downloadInfo.getPosition()); + mDownloadInfoList.add(downloadInfo.getPosition(),downloadInfo); + mAdapter.notifyItemChanged(downloadInfo.getPosition()); + }else if(status == Constant.TYPE_DOWNLOAD_SUCCESS){//歌曲下载成功 + resetDownloadInfoList(); + mAdapter.notifyDataSetChanged(); + }else if(status == Constant.TYPE_DOWNLOAD_CANCELED){//下载取消 + resetDownloadInfoList(); + mAdapter.notifyDataSetChanged(); + }else if(status == Constant.TYPE_DOWNLOAD_ADD){//添加了正在下载歌曲 + resetDownloadInfoList(); + } + } + + + //重新从数据库中读取需要下载的歌曲 + private void resetDownloadInfoList(){ + mDownloadInfoList.clear(); + List temp = LitePal.findAll(DownloadInfo.class,true); + if(temp.size()!=0){ + mDownloadInfoList.addAll(temp); + } + + } + + + + @Override + public void onDestroyView() { + super.onDestroyView(); + EventBus.getDefault().unregister(this); + unbinder.unbind(); + } +} diff --git a/app/src/main/java/com/example/musicplayer/view/main/HistoryFragment.java b/app/src/main/java/com/example/musicplayer/view/main/history/HistoryFragment.java similarity index 95% rename from app/src/main/java/com/example/musicplayer/view/main/HistoryFragment.java rename to app/src/main/java/com/example/musicplayer/view/main/history/HistoryFragment.java index 73be7b6..657ec6b 100644 --- a/app/src/main/java/com/example/musicplayer/view/main/HistoryFragment.java +++ b/app/src/main/java/com/example/musicplayer/view/main/history/HistoryFragment.java @@ -1,4 +1,4 @@ -package com.example.musicplayer.view.main; +package com.example.musicplayer.view.main.history; import android.content.ComponentName; import android.content.Context; @@ -67,7 +67,7 @@ public class HistoryFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_love_music, container, false); + View view = inflater.inflate(R.layout.fragment_love, container, false); EventBus.getDefault().register(this); mRecycler = view.findViewById(R.id.recycler_love_songs); mBackIv = view.findViewById(R.id.iv_back); @@ -117,8 +117,9 @@ public class HistoryFragment extends Fragment { song.setOnline(history.isOnline()); song.setUrl(history.getUrl()); song.setImgUrl(history.getPic()); - song.setCurrent(position); + song.setPosition(position); song.setDuration(history.getDuration()); + song.setMediaId(history.getMediaId()); song.setListType(Constant.LIST_TYPE_HISTORY); FileUtil.saveSong(song); diff --git a/app/src/main/java/com/example/musicplayer/view/main/LocalFragment.java b/app/src/main/java/com/example/musicplayer/view/main/local/LocalFragment.java similarity index 96% rename from app/src/main/java/com/example/musicplayer/view/main/LocalFragment.java rename to app/src/main/java/com/example/musicplayer/view/main/local/LocalFragment.java index a77b925..19081da 100644 --- a/app/src/main/java/com/example/musicplayer/view/main/LocalFragment.java +++ b/app/src/main/java/com/example/musicplayer/view/main/local/LocalFragment.java @@ -1,4 +1,4 @@ -package com.example.musicplayer.view.main; +package com.example.musicplayer.view.main.local; import android.content.ComponentName; import android.content.Context; @@ -97,7 +97,7 @@ public class LocalFragment extends BaseMvpFragment implements IL public void onMessageEvent(SongLocalEvent event){ songAdapter.notifyDataSetChanged(); if (FileUtil.getSong() != null) { - layoutManager.scrollToPositionWithOffset(FileUtil.getSong().getCurrent() + 4, mRecycler.getHeight()); + layoutManager.scrollToPositionWithOffset(FileUtil.getSong().getPosition() + 4, mRecycler.getHeight()); } } @@ -115,7 +115,7 @@ public class LocalFragment extends BaseMvpFragment implements IL @Override protected int getLayoutId() { - return R.layout.fragment_local_music; + return R.layout.fragment_local; } @@ -137,7 +137,7 @@ public class LocalFragment extends BaseMvpFragment implements IL song.setSinger(mp3Info.getSinger()); song.setUrl(mp3Info.getUrl()); song.setDuration(mp3Info.getDuration()); - song.setCurrent(position); + song.setPosition(position); song.setOnline(false); song.setSongId(mp3Info.getSongId()); song.setListType(Constant.LIST_TYPE_LOCAL); @@ -179,7 +179,7 @@ public class LocalFragment extends BaseMvpFragment implements IL songAdapter = new SongAdapter(mActivity, mLocalSongsList); mRecycler.setAdapter(songAdapter); if (FileUtil.getSong() != null) { - layoutManager.scrollToPositionWithOffset(FileUtil.getSong().getCurrent() - 4, mRecycler.getHeight()); + layoutManager.scrollToPositionWithOffset(FileUtil.getSong().getPosition() - 4, mRecycler.getHeight()); } songAdapter.setOnItemClickListener(position -> { //将点击的序列化到本地 @@ -189,7 +189,7 @@ public class LocalFragment extends BaseMvpFragment implements IL song.setSinger(mp3Info.getSinger()); song.setUrl(mp3Info.getUrl()); song.setDuration(mp3Info.getDuration()); - song.setCurrent(position); + song.setPosition(position); song.setOnline(false); song.setSongId(mp3Info.getSongId()); song.setListType(Constant.LIST_TYPE_LOCAL); diff --git a/app/src/main/java/com/example/musicplayer/view/search/AlbumSongFragment.java b/app/src/main/java/com/example/musicplayer/view/search/AlbumSongFragment.java index 3d4dbef..758138e 100644 --- a/app/src/main/java/com/example/musicplayer/view/search/AlbumSongFragment.java +++ b/app/src/main/java/com/example/musicplayer/view/search/AlbumSongFragment.java @@ -23,6 +23,7 @@ import com.example.musicplayer.app.Constant; import com.example.musicplayer.base.fragment.BaseMvpFragment; import com.example.musicplayer.contract.IAlbumSongContract; import com.example.musicplayer.entiy.AlbumSong; +import com.example.musicplayer.entiy.DownloadSong; import com.example.musicplayer.entiy.Song; import com.example.musicplayer.event.SongAlbumEvent; import com.example.musicplayer.presenter.AlbumSongPresenter; @@ -190,12 +191,15 @@ public class AlbumSongFragment extends BaseMvpFragment imple song.setSongId(dataBean.getSongmid()); song.setSinger(getSinger(dataBean)); song.setSongName(dataBean.getSongname()); - song.setCurrent(position); + song.setPosition(position); song.setDuration(dataBean.getInterval()); song.setOnline(true); song.setListType(Constant.LIST_TYPE_ONLINE); song.setImgUrl(Api.ALBUM_PIC+dataBean.getAlbummid()+ Api.JPG); song.setUrl(null); + song.setMediaId(dataBean.getStrMediaMid()); + //判断是否已经下载 + song.setDownload(LitePal.where("songId=?", dataBean.getSongmid()).find(DownloadSong.class).size() != 0); FileUtil.saveSong(song); mPlayStatusBinder.play(Constant.LIST_TYPE_ONLINE); diff --git a/app/src/main/java/com/example/musicplayer/view/search/ContentFragment.java b/app/src/main/java/com/example/musicplayer/view/search/ContentFragment.java index 285a8b8..89bb73f 100644 --- a/app/src/main/java/com/example/musicplayer/view/search/ContentFragment.java +++ b/app/src/main/java/com/example/musicplayer/view/search/ContentFragment.java @@ -9,7 +9,7 @@ import android.view.View; import android.view.ViewGroup; import com.example.musicplayer.R; -import com.example.musicplayer.adapter.SearchAdapter; +import com.example.musicplayer.adapter.TabAdapter; import java.util.ArrayList; import java.util.List; @@ -23,7 +23,7 @@ public class ContentFragment extends Fragment { private List mTitleList; private List mFragments; private ViewPager mPager; - private SearchAdapter mAdapter; + private TabAdapter mAdapter; private TabLayout mTabLayout; private String[] mTitles = {"歌曲", "专辑"}; private String[] mTypes = {"song", "album"}; @@ -48,18 +48,12 @@ public class ContentFragment extends Fragment { return view; } - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - } - private void initTab() { for (int i = 0; i < mTitles.length; i++) { mTitleList.add(mTitles[i]); mFragments.add(SearchContentFragment.newInstance(mSeek, mTypes[i])); } - mAdapter = new SearchAdapter(getChildFragmentManager(), mFragments, mTitleList); + mAdapter = new TabAdapter(getChildFragmentManager(), mFragments, mTitleList); mPager.setAdapter(mAdapter); mTabLayout.setupWithViewPager(mPager); diff --git a/app/src/main/java/com/example/musicplayer/view/search/SearchContentFragment.java b/app/src/main/java/com/example/musicplayer/view/search/SearchContentFragment.java index e4910ca..7970419 100644 --- a/app/src/main/java/com/example/musicplayer/view/search/SearchContentFragment.java +++ b/app/src/main/java/com/example/musicplayer/view/search/SearchContentFragment.java @@ -20,6 +20,7 @@ import com.example.musicplayer.app.Constant; import com.example.musicplayer.base.fragment.BaseLoadingFragment; import com.example.musicplayer.contract.ISearchContentContract; import com.example.musicplayer.entiy.Album; +import com.example.musicplayer.entiy.DownloadSong; import com.example.musicplayer.entiy.SearchSong; import com.example.musicplayer.entiy.Song; import com.example.musicplayer.event.OnlineSongChangeEvent; @@ -27,6 +28,7 @@ import com.example.musicplayer.event.OnlineSongErrorEvent; import com.example.musicplayer.presenter.SearchContentPresenter; import com.example.musicplayer.service.PlayerService; import com.example.musicplayer.util.CommonUtil; +import com.example.musicplayer.util.DownloadUtil; import com.example.musicplayer.util.FileUtil; import com.github.jdsjlzx.recyclerview.LRecyclerView; import com.github.jdsjlzx.recyclerview.LRecyclerViewAdapter; @@ -34,6 +36,7 @@ import com.github.jdsjlzx.recyclerview.LRecyclerViewAdapter; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import org.litepal.LitePal; import java.util.ArrayList; import java.util.List; @@ -165,12 +168,12 @@ public class SearchContentFragment extends BaseLoadingFragment + android:text="@string/welcome_text"/> diff --git a/app/src/main/res/layout/fragment_download.xml b/app/src/main/res/layout/fragment_download.xml new file mode 100644 index 0000000..42aa180 --- /dev/null +++ b/app/src/main/res/layout/fragment_download.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_download_ing.xml b/app/src/main/res/layout/fragment_download_ing.xml new file mode 100644 index 0000000..46d5bb0 --- /dev/null +++ b/app/src/main/res/layout/fragment_download_ing.xml @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_download_music.xml b/app/src/main/res/layout/fragment_download_music.xml new file mode 100644 index 0000000..e80efc1 --- /dev/null +++ b/app/src/main/res/layout/fragment_download_music.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_local_music.xml b/app/src/main/res/layout/fragment_local.xml similarity index 100% rename from app/src/main/res/layout/fragment_local_music.xml rename to app/src/main/res/layout/fragment_local.xml diff --git a/app/src/main/res/layout/fragment_love_music.xml b/app/src/main/res/layout/fragment_love.xml similarity index 100% rename from app/src/main/res/layout/fragment_love_music.xml rename to app/src/main/res/layout/fragment_love.xml diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index c4a62e1..738e8d5 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -38,7 +38,7 @@ android:focusable="true" android:focusableInTouchMode="true" android:paddingStart="15dp" - android:hint="周杰伦" + android:hint="@string/search_singer" android:textColor="@color/white" android:textSize="16sp" /> diff --git a/app/src/main/res/layout/function.xml b/app/src/main/res/layout/function.xml index b3593a4..2912271 100644 --- a/app/src/main/res/layout/function.xml +++ b/app/src/main/res/layout/function.xml @@ -116,11 +116,13 @@ android:textColor="@drawable/selector_linear_click"/> + android:orientation="vertical" + android:focusable="true"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/seek.xml b/app/src/main/res/layout/seek.xml index 6fd0402..62b7085 100644 --- a/app/src/main/res/layout/seek.xml +++ b/app/src/main/res/layout/seek.xml @@ -17,7 +17,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="我" + android:text="@string/me" android:gravity="center" android:textColor="@color/musicStyle" android:textSize="22sp"/> @@ -26,22 +26,14 @@ android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" - android:text="听" + android:text="@string/listen" android:textSize="20sp" android:textColor="@color/white_blue"/> - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5f797b5..fbdad42 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -49,5 +49,18 @@ 顺序播放 随机播放 单曲循环 +  /  + + //download + 该歌曲已下载 + 取消下载 + 确定不再下载吗? + 删除 + 邓紫棋 + + + + 随心所动,开启你的音乐之旅 + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 978f837..da21481 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -43,6 +43,12 @@ @drawable/ic_seekbar_thumb + +