有内存泄露
This commit is contained in:
yutou 2020-11-24 18:32:19 +08:00
parent c7c6a07e45
commit 26bdcffb68
21 changed files with 826 additions and 85 deletions

View File

@ -40,4 +40,8 @@ dependencies {
implementation 'androidx.palette:palette:1.0.0' implementation 'androidx.palette:palette:1.0.0'
implementation 'com.github.zrunker:ZTextView:v1.0.2' implementation 'com.github.zrunker:ZTextView:v1.0.2'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'
implementation 'com.kaopiz:kprogresshud:1.2.0'
implementation 'com.ogaclejapan.smarttablayout:library:2.0.0@aar'
} }

View File

@ -15,7 +15,7 @@
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true">
<activity <activity
android:name=".views.OpenActivity" android:name=".views.OpenActivity"
android:theme="@style/Theme.AppCompat.NoActionBar"> android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -25,7 +25,11 @@
<activity <activity
android:name=".views.MainActivity" android:name=".views.MainActivity"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
android:theme="@style/Theme.AppCompat.NoActionBar" /> android:theme="@style/Theme.AppCompat.DayNight.NoActionBar" />
<activity
android:name=".views.PlayLibsActivity"
android:fitsSystemWindows="true"
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar" />
<service <service
android:name=".services.MusicService" android:name=".services.MusicService"

View File

@ -1,14 +1,18 @@
package com.yutou.nas_music_player.containers; package com.yutou.nas_music_player.Datas;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.util.Base64; import android.util.Base64;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.yutou.nas_music_player.Interfaces.DownloadInterface; import com.yutou.nas_music_player.Interfaces.DownloadInterface;
import com.yutou.nas_music_player.Interfaces.NetworkInterface; import com.yutou.nas_music_player.Interfaces.NetworkInterface;
import com.yutou.nas_music_player.MyApplication;
import com.yutou.nas_music_player.R;
import com.yutou.nas_music_player.tools.AppTools;
import com.yutou.nas_music_player.tools.NetworkTool; import com.yutou.nas_music_player.tools.NetworkTool;
import com.yutou.nas_music_player.tools.StringUtil; import com.yutou.nas_music_player.tools.StringUtil;
@ -149,7 +153,7 @@ public class MusicData {
} }
public String getPlayFileBase64() { public String getPlayFileBase64() {
return new String(Base64.encode(file.getBytes(), Base64.DEFAULT)); return new String(Base64.encode(file.replace("\r\n", "").getBytes(), Base64.DEFAULT));
} }
public String getPlayUrl() { public String getPlayUrl() {
@ -166,6 +170,11 @@ public class MusicData {
if (isDownloadImg) { if (isDownloadImg) {
return null; return null;
} }
img = AppTools.getSaveBitmap(getPlayFileBase64());
if (img != null) {
return img;
}
img = null;
isDownloadImg = true; isDownloadImg = true;
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("fileName", getPlayFileBase64()); json.put("fileName", getPlayFileBase64());
@ -173,9 +182,15 @@ public class MusicData {
@Override @Override
public void httpGetData(Object data, int state) { public void httpGetData(Object data, int state) {
JSONObject json = JSONObject.parseObject(data.toString()); JSONObject json = JSONObject.parseObject(data.toString());
try {
if (json.getInteger("code") == 0) { if (json.getInteger("code") == 0) {
byte[] bytes = json.getBytes("data"); byte[] bytes = json.getBytes("data");
img = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); img = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
AppTools.saveBitmap(img,getPlayFileBase64());
}
} catch (Exception e) {
e.printStackTrace();
img = BitmapFactory.decodeResource(MyApplication.application.getResources(), R.mipmap.ic_launcher);
} }
} }

View File

@ -0,0 +1,34 @@
package com.yutou.nas_music_player.Datas;
import java.util.ArrayList;
import java.util.List;
/**
* 播放记录
*/
public class PreviousPlayerList {
private static final int INDEX=10;//记录十条
private List<MusicData> list;
public PreviousPlayerList(){
list=new ArrayList<>();
}
public void add(MusicData musicData){
MusicData tmp = null;
for (MusicData data : list) {
if(data.getFile().equals(musicData.getFile())){
tmp=data;
}
}
if(tmp!=null){
list.remove(tmp);
}
list.add(musicData);
}
public MusicData getMusicData(){
if(list.size()>1){
list.remove(list.size()-1);
}
return list.get(list.size()-1);
}
}

View File

@ -53,7 +53,6 @@ public class MediaBrowserHelper {
public void regPlayListener(MediaControllerCompat.Callback playListener) { public void regPlayListener(MediaControllerCompat.Callback playListener) {
callbacks.add(playListener); callbacks.add(playListener);
} }
private class MediaBrowserConnectionCallback extends MediaBrowserCompat.ConnectionCallback { private class MediaBrowserConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
@Override @Override
public void onConnected() { public void onConnected() {

View File

@ -1,11 +1,17 @@
package com.yutou.nas_music_player.containers; package com.yutou.nas_music_player.containers;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.os.Build;
import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.MediaMetadataCompat;
import android.widget.Toast;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.yutou.nas_music_player.Datas.MusicData;
import com.yutou.nas_music_player.Datas.PreviousPlayerList;
import com.yutou.nas_music_player.Interfaces.NetworkInterface; import com.yutou.nas_music_player.Interfaces.NetworkInterface;
import com.yutou.nas_music_player.MyApplication;
import com.yutou.nas_music_player.tools.ConfigTools;
import com.yutou.nas_music_player.tools.NetworkTool; import com.yutou.nas_music_player.tools.NetworkTool;
import com.yutou.nas_music_player.tools.StringUtil; import com.yutou.nas_music_player.tools.StringUtil;
@ -18,23 +24,26 @@ import java.util.Random;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import static android.media.MediaPlayer.SEEK_PREVIOUS_SYNC;
public class MusicContainer { public class MusicContainer {
public static final int PLAY_MODEL_RANDOM = 0; public static final int PLAY_MODEL_RANDOM = 0;//随机
public static final int PLAY_MODEL_LIST = 1; public static final int PLAY_MODEL_ORDER = 1;//顺序
public static final int PLAY_MODEL_TMP_LIST = 2; public static final int PLAY_MODEL_ONE_LOOP = 2;//单曲循环
public static final int PLAY_MODEL_ALBUM = 3; public static final int PLAY_MODEL_LOOP = 3;//列表循环
private static MusicContainer container; private static MusicContainer container;
private MusicLibs libs; private MusicLibs libs;
private MediaPlayer mediaPlayer; private MediaPlayer mediaPlayer;
private int playIndex = 0; private int playIndex = 0;
private MusicData nowPlayData = null; private MusicData nowPlayData = null;
private final MusicLibsInitInterface initInterface; private MusicLibsInitInterface initInterface;
private List<MediaPlayer.OnCompletionListener> completionListener; private List<MediaPlayer.OnCompletionListener> completionListener;
private MediaBrowserHelper browserHelper; private MediaBrowserHelper browserHelper;
private List<MusicData> playList, tmpList; private List<MusicData> playList, tmpList;
private Map<String, List<MusicData>> albumMapList; private Map<String, List<MusicData>> albumMapList;
private int playModel = PLAY_MODEL_RANDOM; private int playModel = PLAY_MODEL_RANDOM;
private PreviousPlayerList previousPlayerList;
private MusicContainer(MusicLibsInitInterface initInterface) { private MusicContainer(MusicLibsInitInterface initInterface) {
this.initInterface = initInterface; this.initInterface = initInterface;
@ -42,6 +51,8 @@ public class MusicContainer {
playList = new ArrayList<>(); playList = new ArrayList<>();
tmpList = new ArrayList<>(); tmpList = new ArrayList<>();
albumMapList = new HashMap<>(); albumMapList = new HashMap<>();
previousPlayerList = new PreviousPlayerList();
playIndex = ConfigTools.getPreferences().getInt("playIndex", 0);
initMediaPlayer(); initMediaPlayer();
libs = new MusicLibs(); libs = new MusicLibs();
} }
@ -52,13 +63,37 @@ public class MusicContainer {
private void initMediaPlayer() { private void initMediaPlayer() {
completionListener = new ArrayList<>(); completionListener = new ArrayList<>();
mediaPlayer.setLooping(false);
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override @Override
public void onCompletion(MediaPlayer mp) { public void onCompletion(MediaPlayer mp) {
System.out.println(nowPlayData.getFile());
int tmp=((int)(nowPlayData.getDurationAsDouble()*1000)-mp.getCurrentPosition());
if(tmp>1000){
System.out.println("发生跳曲行为");
mp.start();
seekTo(mp.getCurrentPosition());
}else {
System.out.println("自动播放完成,进行下一曲");
playTimer.cancel(); playTimer.cancel();
playTimer = null; playTimer = null;
browserHelper.getTransportControls().skipToNext(); browserHelper.getTransportControls().skipToNext();
} }
}
});
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
System.out.println("播放错误: what="+what+" extra="+extra);
return false;
}
});
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
System.out.println("调用了onPrepared");
}
}); });
} }
@ -110,13 +145,15 @@ public class MusicContainer {
isPause = false; isPause = false;
return; return;
} }
ConfigTools.getPreferences().edit().putInt("playIndex", playIndex).apply();
nowPlayData = data; nowPlayData = data;
String url = data.getPlayUrl(); String url = data.getPlayUrl();
previousPlayerList.add(data);
try { try {
if (mediaPlayer.isPlaying()) { if (mediaPlayer.isPlaying()) {
mediaPlayer.stop(); mediaPlayer.stop();
mediaPlayer.reset();
} }
mediaPlayer.reset();
mediaPlayer.setDataSource(url); mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); mediaPlayer.prepare();
mediaPlayer.start(); mediaPlayer.start();
@ -133,11 +170,23 @@ public class MusicContainer {
} }
}, 0, 1000); }, 0, 1000);
} }
ConfigTools.getPreferences().edit().putString(ConfigTools.previous_music, JSONObject.toJSONString(data)).apply();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public void seekTo(long pos) {
System.out.println("跳帧:" + pos);
if (mediaPlayer.isPlaying()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mediaPlayer.seekTo(pos, SEEK_PREVIOUS_SYNC);
} else {
mediaPlayer.seekTo((int) pos);
}
}
}
private Timer playTimer; private Timer playTimer;
public MediaMetadataCompat getNowPlayMetadataCompat() { public MediaMetadataCompat getNowPlayMetadataCompat() {
@ -162,7 +211,13 @@ public class MusicContainer {
return 8888L; return 8888L;
} }
private MediaMetadataCompat metadataCompat;
private String metaDataFile;
public MediaMetadataCompat getMetadataCompat(MusicData data) { public MediaMetadataCompat getMetadataCompat(MusicData data) {
if (data.getFile().equals(metaDataFile)) {
return metadataCompat;
}
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder(); MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
builder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, data.getTitle()); builder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, data.getTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, data.getArtist()); builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, data.getArtist());
@ -172,12 +227,13 @@ public class MusicContainer {
builder.putLong(MediaMetadataCompat.METADATA_KEY_YEAR, getYear(data.getYear())); builder.putLong(MediaMetadataCompat.METADATA_KEY_YEAR, getYear(data.getYear()));
builder.putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, Long.parseLong(data.getTrack())); builder.putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, Long.parseLong(data.getTrack()));
builder.putLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER, Long.parseLong(data.getDisc_no())); builder.putLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER, Long.parseLong(data.getDisc_no()));
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, ((int) data.getDurationAsDouble()) * 1000); builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, ((int) (data.getDurationAsDouble() * 1000)));
if (data.getImg() != null) { if (data.getImg() != null) {
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, data.getImg()); builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, data.getImg());
} }
builder.putString("md5", data.getMd5()); builder.putString("md5", data.getMd5());
return builder.build(); metadataCompat = builder.build();
return metadataCompat;
} }
public static MusicLibs getLibs() { public static MusicLibs getLibs() {
@ -191,16 +247,20 @@ public class MusicContainer {
mediaPlayer.pause(); mediaPlayer.pause();
} }
/**
* 播放下一曲
*/
public void playNext() { public void playNext() {
System.out.println("播放模式:" + playModel);
switch (playModel) { switch (playModel) {
case PLAY_MODEL_LIST: case PLAY_MODEL_ORDER:
playList(true); playOrder(false);
break; break;
case PLAY_MODEL_TMP_LIST: case PLAY_MODEL_ONE_LOOP:
playTmpList(true); playOneLoop();
break; break;
case PLAY_MODEL_ALBUM: case PLAY_MODEL_LOOP:
playAlbumList(true); playOrder(true);
break; break;
case PLAY_MODEL_RANDOM: case PLAY_MODEL_RANDOM:
default: default:
@ -208,18 +268,73 @@ public class MusicContainer {
} }
} }
private void playList(boolean isNext) { /**
* 播放上一曲
*/
public void playPrevious() {
playIndex--;
MusicData data = previousPlayerList.getMusicData();
if (data != null) {
play(data);
} else {
Toast.makeText(MyApplication.application, "没有上一曲记录", Toast.LENGTH_LONG).show();
}
} }
private void playTmpList(boolean isNext) { /**
* 顺序播放
*
* @param isLoop 循环播放列表
*/
private void playOrder(boolean isLoop) {
if (tmpList.size() != 0) {//有插队列表优先播放
play(tmpList.get(0));//后插入先播放
tmpList.remove(0);
} else if (playList.size() == 0) {//播放列表为空以所有歌列表顺序播放
if (libs.mainData.size() > (playIndex + 1)) {
playIndex++;
} else {
playIndex = 0;
}
play(libs.mainData.get(playIndex));
} else {//播放列表中的歌单
if (playList.size() > (playIndex + 1)) {
playIndex++;
}
if (isLoop) {
playIndex = 0;
play(playList.get(playIndex));
} else {
playList.clear();//列表播放完了清空
playOfAllRandom();//暂时先设计成后续随机播放毕竟列表已经空了
}
}
} }
/**
* 单曲循环
*/
private void playOneLoop() {
play(nowPlayData);
}
/**
* 专辑播放
*
* @param isNext 下一首
*/
private void playAlbumList(boolean isNext) { private void playAlbumList(boolean isNext) {
} }
public List<MusicData> getPlayList(){
if(!tmpList.isEmpty()){
return tmpList;
}
if(!playList.isEmpty()){
return playList;
}
return libs.mainData;
}
public class MusicLibs { public class MusicLibs {
private List<MusicData> mainData; private List<MusicData> mainData;
@ -245,12 +360,13 @@ public class MusicContainer {
} }
System.out.println("获取列表完成"); System.out.println("获取列表完成");
for (MusicData mainDatum : mainData) { for (MusicData mainDatum : mainData) {
if(StringUtil.isEmpty(mainDatum.getMd5())){ if (StringUtil.isEmpty(mainDatum.getMd5())) {
System.out.println(mainDatum.getFile()); System.out.println(mainDatum.getFile());
} }
} }
if (initInterface != null) { if (initInterface != null) {
initInterface.init(); initInterface.init();
initInterface = null;
} }
} }
} }
@ -262,14 +378,30 @@ public class MusicContainer {
}); });
} }
public MusicData findMusic(String md5) { public MusicData findMusic(String md5,List<MusicData> list) {
for (MusicData data : mainData) { for (MusicData data : list) {
if (data.getMd5() == null) {
continue;
}
if (md5.contains(data.getMd5())) { if (md5.contains(data.getMd5())) {
return data; return data;
} }
} }
return null; return null;
} }
public int findMusicIndex(String md5, List<MusicData> list) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getMd5() == null) {
continue;
}
if (md5.contains((list.get(i).getMd5()))) {
return i;
}
}
return 0;
}
} }
public interface MusicLibsInitInterface { public interface MusicLibsInitInterface {

View File

@ -1,12 +1,8 @@
package com.yutou.nas_music_player.services; package com.yutou.nas_music_player.services;
import android.app.Notification; import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.v4.media.MediaBrowserCompat; import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.MediaMetadataCompat;
@ -19,15 +15,10 @@ import androidx.media.MediaBrowserServiceCompat;
import com.yutou.nas_music_player.containers.MediaNotificationManager; import com.yutou.nas_music_player.containers.MediaNotificationManager;
import com.yutou.nas_music_player.containers.MusicContainer; import com.yutou.nas_music_player.containers.MusicContainer;
import com.yutou.nas_music_player.containers.MusicData; import com.yutou.nas_music_player.Datas.MusicData;
import com.yutou.nas_music_player.tools.AppData;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import static android.media.MediaPlayer.SEEK_PREVIOUS_SYNC;
public class MusicService extends MediaBrowserServiceCompat { public class MusicService extends MediaBrowserServiceCompat {
public MediaSessionCompat mediaSession; public MediaSessionCompat mediaSession;
@ -78,7 +69,7 @@ public class MusicService extends MediaBrowserServiceCompat {
result.sendResult(mediaItems); result.sendResult(mediaItems);
} }
public void onSeekTo(long pos) { public void seekToNotification(long pos) {
MusicData data = MusicContainer.getInstance().getNowPlayData(); MusicData data = MusicContainer.getInstance().getNowPlayData();
MediaMetadataCompat metadataCompat = MusicContainer.getInstance().getMetadataCompat(data); MediaMetadataCompat metadataCompat = MusicContainer.getInstance().getMetadataCompat(data);
Notification notification = notificationManager.getNotification(metadataCompat, builderState(pos).build(), getSessionToken()); Notification notification = notificationManager.getNotification(metadataCompat, builderState(pos).build(), getSessionToken());
@ -163,13 +154,9 @@ public class MusicService extends MediaBrowserServiceCompat {
@Override @Override
public void onSeekTo(long pos) { public void onSeekTo(long pos) {
super.onSeekTo(pos); super.onSeekTo(pos);
System.out.println("SeeTo :"+pos); System.out.println("接收到跳帧指令~~~");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { MusicContainer.getInstance().seekTo(pos);
MusicContainer.getInstance().getMediaPlayer().seekTo(pos,SEEK_PREVIOUS_SYNC); MusicService.this.seekToNotification(pos);
}else{
MusicContainer.getInstance().getMediaPlayer().seekTo((int) pos);
}
MusicService.this.onSeekTo(pos);
} }
@Override @Override
@ -182,6 +169,8 @@ public class MusicService extends MediaBrowserServiceCompat {
@Override @Override
public void onSkipToPrevious() { public void onSkipToPrevious() {
super.onSkipToPrevious(); super.onSkipToPrevious();
MusicContainer.getInstance().playPrevious();
updateNotification();
} }
@Override @Override
@ -196,7 +185,7 @@ public class MusicService extends MediaBrowserServiceCompat {
@Override @Override
public void onCompletion(MediaPlayer mp) { public void onCompletion(MediaPlayer mp) {
onSeekTo(mp.getCurrentPosition()); seekToNotification(mp.getCurrentPosition());
} }
} }
} }

View File

@ -3,9 +3,14 @@ package com.yutou.nas_music_player.tools;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import com.yutou.nas_music_player.MyApplication;
import java.io.File;
public class AppData { public class AppData {
public static String download_dir="downloads"; public static String download_dir="downloads";
public static String dir= MyApplication.application.getFilesDir() + File.separator;
public static boolean isDebug=true; public static boolean isDebug=true;
public static Handler handler=new Handler(Looper.getMainLooper()); public static Handler handler=new Handler(Looper.getMainLooper());
} }

View File

@ -0,0 +1,86 @@
package com.yutou.nas_music_player.tools;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.kaopiz.kprogresshud.KProgressHUD;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.security.MessageDigest;
public class AppTools {
public static KProgressHUD showLoading(Context context){
return KProgressHUD.create(context)
.setStyle(KProgressHUD.Style.SPIN_INDETERMINATE)
.setDetailsLabel("loading...")
.setCancellable(true)
.setAnimationSpeed(2)
.setDimAmount(0.5f)
.show();
}
public static void saveBitmap(final Bitmap bitmap, final String saveKey){
new Thread(new Runnable() {
@Override
public void run() {
String md5=getMD5(saveKey);
File path=new File(AppData.dir+"img_cache"+File.separator);
if(!path.exists()){
path.mkdirs();
}
File image=new File(AppData.dir+"img_cache"+File.separator+md5);
try {
if(!image.exists()){
image.createNewFile();
}
FileOutputStream outputStream=new FileOutputStream(image);
bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
outputStream.flush();
outputStream.close();
ConfigTools.getPreferences().edit().putString("img_"+md5,image.getAbsolutePath()).apply();
} catch (Exception e) {
e.printStackTrace();
System.out.println(image.getAbsolutePath());
}
}
}).start();
}
public static Bitmap getSaveBitmap(String saveKey){
String path=ConfigTools.getPreferences().getString(getMD5(saveKey),null);
if(path==null){
return null;
}
return BitmapFactory.decodeFile(path);
}
public static String getMD5(String data) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(data.getBytes());
return bytesToHexString(digest.digest());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (byte aSrc : src) {
int v = aSrc & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}

View File

@ -47,7 +47,7 @@ public class NetworkTool {
private static final String TAG = NetworkTool.class.getName(); private static final String TAG = NetworkTool.class.getName();
private static NetworkTool network; private static NetworkTool network;
public boolean isNet = true; public boolean isNet = true;
public static String donwloadPath = MyApplication.application.getFilesDir() + File.separator + AppData.download_dir + File.separator; public static String donwloadPath = AppData.dir + AppData.download_dir + File.separator;
private NetworkTool() { private NetworkTool() {
if (StringUtil.isEmpty(HOME)) { if (StringUtil.isEmpty(HOME)) {
@ -101,6 +101,10 @@ public class NetworkTool {
HttpURLConnection connection = (HttpURLConnection) new URL(url + "?" + toGetSplice(body)).openConnection(); HttpURLConnection connection = (HttpURLConnection) new URL(url + "?" + toGetSplice(body)).openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
connection.connect(); connection.connect();
if(connection.getResponseCode()!=200){
networkInterface.httpError(new RuntimeException("http code to :"+connection.getResponseCode()));
return;
}
String tmp; String tmp;
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
while ((tmp = reader.readLine()) != null) { while ((tmp = reader.readLine()) != null) {

View File

@ -1,17 +1,23 @@
package com.yutou.nas_music_player.views; package com.yutou.nas_music_player.views;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.util.Pair;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat; import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat; import android.support.v4.media.session.PlaybackStateCompat;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.Window;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -19,14 +25,18 @@ import android.widget.Toast;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.RequestOptions;
import com.kaopiz.kprogresshud.KProgressHUD;
import com.yutou.nas_music_player.R; import com.yutou.nas_music_player.R;
import com.yutou.nas_music_player.containers.MediaBrowserHelper; import com.yutou.nas_music_player.containers.MediaBrowserHelper;
import com.yutou.nas_music_player.containers.MusicContainer; import com.yutou.nas_music_player.containers.MusicContainer;
import com.yutou.nas_music_player.containers.MusicData; import com.yutou.nas_music_player.Datas.MusicData;
import com.yutou.nas_music_player.tools.AppData; import com.yutou.nas_music_player.tools.AppData;
import com.yutou.nas_music_player.tools.AppTools;
import com.yutou.nas_music_player.tools.ConfigTools; import com.yutou.nas_music_player.tools.ConfigTools;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -35,46 +45,94 @@ import jp.wasabeef.glide.transformations.BlurTransformation;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation; import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
private ImageButton play, previous, next; private ImageButton play, previous, next, playModel;
private MediaBrowserHelper browserHelper; private MediaBrowserHelper browserHelper;
private ImageView album_image, background_image; private ImageView album_image, background_image;
private MarqueeTextView title, album, artist; private MarqueeTextView title, album, artist;
private TextView positionTime, durationTime, bitRate; private TextView positionTime, durationTime, bitRate;
private SeekBar seekBar; private SeekBar seekBar;
private Handler handler;
private KProgressHUD hud;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setBarColor(android.R.color.transparent); setBarColor(android.R.color.transparent);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
handler = new Handler();
initView(); initView();
play.setOnClickListener(new View.OnClickListener() { play.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (hud != null) {
hud.dismiss();
hud = null;
}
hud = AppTools.showLoading(MainActivity.this);
handler.post(new Runnable() {
@Override
public void run() {
if (browserHelper.isPlayer()) { if (browserHelper.isPlayer()) {
browserHelper.getTransportControls().pause(); browserHelper.getTransportControls().pause();
} else { } else {
browserHelper.getTransportControls().play(); browserHelper.getTransportControls().play();
} }
if (hud != null && hud.isShowing()) {
hud.dismiss();
hud = null;
}
}
});
} }
}); });
next.setOnClickListener(new View.OnClickListener() { next.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (hud != null) {
hud.dismiss();
hud = null;
}
hud = AppTools.showLoading(MainActivity.this);
handler.post(new Runnable() {
@Override
public void run() {
browserHelper.getTransportControls().skipToNext(); browserHelper.getTransportControls().skipToNext();
if (hud != null && hud.isShowing()) {
hud.dismiss();
hud = null;
}
}
});
} }
}); });
previous.setOnClickListener(new View.OnClickListener() { previous.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (hud != null) {
hud.dismiss();
hud = null;
}
hud = AppTools.showLoading(MainActivity.this);
handler.post(new Runnable() {
@Override
public void run() {
browserHelper.getTransportControls().skipToPrevious(); browserHelper.getTransportControls().skipToPrevious();
if (hud != null && hud.isShowing()) {
hud.dismiss();
hud = null;
}
}
});
} }
}); });
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override @Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (browserHelper.getTransportControls() != null)
browserHelper.getTransportControls().seekTo(progress);
} }
@Override @Override
@ -84,11 +142,70 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
if (hud != null) {
hud.dismiss();
hud = null;
}
hud = AppTools.showLoading(MainActivity.this);
handler.post(new Runnable() {
@Override
public void run() {
if (browserHelper.getTransportControls() != null)
browserHelper.getTransportControls().seekTo(MainActivity.this.seekBar.getProgress());
if (hud != null && hud.isShowing()) {
hud.dismiss();
hud = null;
}
}
});
} }
}); });
playModel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int model = (int) playModel.getTag();
if (model == MusicContainer.PLAY_MODEL_LOOP) {
setPlayModelButton(MusicContainer.PLAY_MODEL_RANDOM);
return;
}
setPlayModelButton(model + 1);
}
});
getWindow().getDecorView().setOnTouchListener(new View.OnTouchListener() {
float downPosition_x = 0, downPosition_y = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
downPosition_x = event.getRawX();
downPosition_y = event.getRawY();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (Math.abs(downPosition_x - event.getRawX()) < 500 && downPosition_y - event.getRawY() > 500) {
Pair<View, String> pImage = Pair.create((View) album_image, "album_image");
Pair<View, String> pPrevious = Pair.create((View) previous, "previous");
Pair<View, String> pPlay = Pair.create((View) play, "play");
Pair<View, String> pNext = Pair.create((View) next, "next");
Pair<View, String> pTitle = Pair.create((View) title, "title");
Pair<View, String> pArtist = Pair.create((View) artist, "artist");
//ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this,list);
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, pImage, pPrevious, pPlay, pNext, pTitle, pArtist).toBundle();
Intent intent = new Intent(
MainActivity.this, PlayLibsActivity.class);
if (bundle != null) {
startActivity(intent, bundle);
} else {
startActivity(intent);
}
}
}
return false;
}
});
browserHelper = new MediaBrowserHelper(this); browserHelper = new MediaBrowserHelper(this);
browserHelper.regPlayListener(new PlayListener()); browserHelper.regPlayListener(new PlayListener());
initData(); initData();
} }
@ -113,17 +230,19 @@ public class MainActivity extends AppCompatActivity {
private void setPlayData(final MusicData data) { private void setPlayData(final MusicData data) {
System.out.println("设置歌曲"); System.out.println("设置歌曲");
System.out.println(data); System.out.println(data);
if(data==null) if (data == null)
return; return;
title.setText(data.getTitle()); title.setText(data.getTitle());
artist.setText(data.getArtist()); artist.setText(data.getArtist());
album.setText(data.getAlbum()); album.setText(data.getAlbum());
bitRate.setText(data.getBitRate() + "kbps / " + data.getSampleRate() + "hz"); bitRate.setText(data.getBitRate() + "kbps / " + data.getSampleRate() + "hz");
seekBar.setMax((int) data.getDurationAsDouble()); seekBar.setMax((int) (data.getDurationAsDouble() * 1000));
int minutes = (int) (data.getDurationAsDouble() / 60); int minutes = (int) (data.getDurationAsDouble() / 60);
int seconds = (int) (data.getDurationAsDouble() % 60); int seconds = (int) (data.getDurationAsDouble() % 60);
durationTime.setText(minutes + ":" + seconds); durationTime.setText(String.format(Locale.CHINA, "%02d", minutes) + ":"
+ String.format(Locale.CHINA, "%02d", seconds));
int model = ConfigTools.getPreferences().getInt("playModel", MusicContainer.PLAY_MODEL_RANDOM);
setPlayModelButton(model);
if (data.getImg() != null) { if (data.getImg() != null) {
setImage(data); setImage(data);
} else { } else {
@ -145,6 +264,26 @@ public class MainActivity extends AppCompatActivity {
} }
private void setPlayModelButton(int model) {
playModel.setTag(model);
MusicContainer.getInstance().setPlayModel(model);
switch (model) {
case MusicContainer.PLAY_MODEL_RANDOM:
playModel.setImageResource(R.drawable.ic_play_random);
break;
case MusicContainer.PLAY_MODEL_ORDER:
playModel.setImageResource(R.drawable.ic_play_list);
break;
case MusicContainer.PLAY_MODEL_ONE_LOOP:
playModel.setImageResource(R.drawable.ic_play_one_loop);
break;
case MusicContainer.PLAY_MODEL_LOOP:
playModel.setImageResource(R.drawable.ic_play_loop);
break;
}
ConfigTools.getPreferences().edit().putInt("playModel", model).apply();
}
private void setImage(MusicData data) { private void setImage(MusicData data) {
album_image.setImageBitmap(data.getImg()); album_image.setImageBitmap(data.getImg());
background_image.setImageBitmap(data.getImg()); background_image.setImageBitmap(data.getImg());
@ -170,6 +309,7 @@ public class MainActivity extends AppCompatActivity {
positionTime = findViewById(R.id.positionTime); positionTime = findViewById(R.id.positionTime);
durationTime = findViewById(R.id.durationTime); durationTime = findViewById(R.id.durationTime);
seekBar = findViewById(R.id.seekBar); seekBar = findViewById(R.id.seekBar);
playModel = findViewById(R.id.playModel);
} }
public void setBarColor(int color) { public void setBarColor(int color) {
@ -182,13 +322,14 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
public void onPlaybackStateChanged(PlaybackStateCompat state) { public void onPlaybackStateChanged(PlaybackStateCompat state) {
super.onPlaybackStateChanged(state); super.onPlaybackStateChanged(state);
System.out.println("播放状态变化:" + state.getState()); System.out.println("播放状态变化:" + state.getPosition() + " " + seekBar.getMax());
if (state.getState() == PlaybackStateCompat.STATE_PLAYING) { if (state.getState() == PlaybackStateCompat.STATE_PLAYING) {
int duration = (int) (state.getPosition() / 1000); int duration = (int) (state.getPosition() / 1000);
int minutes = duration / 60; int minutes = duration / 60;
int seconds = duration % 60; int seconds = duration % 60;
positionTime.setText(minutes + ":" + seconds); positionTime.setText(String.format(Locale.CHINA, "%02d", minutes) + ":"
seekBar.setProgress((int) (state.getPosition() / 1000)); + String.format(Locale.CHINA, "%02d", seconds));
seekBar.setProgress((int) (state.getPosition()));
play.setImageResource(android.R.drawable.ic_media_pause); play.setImageResource(android.R.drawable.ic_media_pause);
} else { } else {
play.setImageResource(android.R.drawable.ic_media_play); play.setImageResource(android.R.drawable.ic_media_play);
@ -199,16 +340,15 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
public void onMetadataChanged(MediaMetadataCompat metadata) { public void onMetadataChanged(MediaMetadataCompat metadata) {
super.onMetadataChanged(metadata); super.onMetadataChanged(metadata);
String md5=null; String md5 = null;
try { try {
System.out.println("播放歌曲变换:"+metadata.getString("md5")); System.out.println("播放歌曲变换:" + metadata.getString("md5"));
md5=metadata.getString("md5"); md5 = metadata.getString("md5");
}catch (Exception e){ } catch (Exception ignored) {
e.printStackTrace();
} }
if (md5 != null) { if (md5 != null) {
setPlayData(MusicContainer.getLibs().findMusic(md5)); setPlayData(MusicContainer.getLibs().findMusic(md5, MusicContainer.getInstance().getPlayList()));
} }
} }

View File

@ -23,7 +23,7 @@ public class OpenActivity extends AppCompatActivity {
public void init() { public void init() {
Intent intent=new Intent(OpenActivity.this,MainActivity.class); Intent intent=new Intent(OpenActivity.this,MainActivity.class);
startActivity(intent); startActivity(intent);
finish(); OpenActivity.this.finish();
} }
}); });
} }

View File

@ -0,0 +1,145 @@
package com.yutou.nas_music_player.views;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.view.Window;
import android.widget.ImageButton;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.yutou.nas_music_player.Datas.MusicData;
import com.yutou.nas_music_player.R;
import com.yutou.nas_music_player.containers.MediaBrowserHelper;
import com.yutou.nas_music_player.containers.MusicContainer;
import com.yutou.nas_music_player.tools.AppData;
import com.yutou.nas_music_player.tools.ConfigTools;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import cc.ibooker.ztextviewlib.MarqueeTextView;
import jp.wasabeef.glide.transformations.BlurTransformation;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class PlayLibsActivity extends AppCompatActivity {
private ImageButton play, previous, next;
private MediaBrowserHelper browserHelper;
private ImageView album_image;
private MarqueeTextView title, artist;
private PlayListener playListener;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_list);
initView();
setPlayData(MusicContainer.getInstance().getNowPlayData());
browserHelper = new MediaBrowserHelper(this);
playListener=new PlayListener();
browserHelper.regPlayListener(playListener);
}
private void initView() {
play = findViewById(R.id.play);
next = findViewById(R.id.next);
previous = findViewById(R.id.previous);
album_image = findViewById(R.id.album_image);
title = findViewById(R.id.title);
artist = findViewById(R.id.artist);
}
private void setImage(MusicData data) {
album_image.setImageBitmap(data.getImg());
Glide.with(this).load(data.getImg())
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(25, 3)))
.into(album_image);
}
@SuppressLint("SetTextI18n")
private void setPlayData(final MusicData data) {
System.out.println("设置歌曲");
System.out.println(data);
if (data == null)
return;
title.setText(data.getTitle());
artist.setText(data.getArtist());
if (data.getImg() != null) {
setImage(data);
} else {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (data.getImg() != null) {
AppData.handler.post(new Runnable() {
@Override
public void run() {
setImage(data);
}
});
cancel();
}
}
}, 0, 100);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
browserHelper=null;
finish();
}
private class PlayListener extends MediaControllerCompat.Callback {
@SuppressLint("SetTextI18n")
@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
super.onPlaybackStateChanged(state);
if (state.getState() == PlaybackStateCompat.STATE_PLAYING) {
play.setImageResource(android.R.drawable.ic_media_pause);
} else {
play.setImageResource(android.R.drawable.ic_media_play);
}
}
@Override
public void onMetadataChanged(MediaMetadataCompat metadata) {
super.onMetadataChanged(metadata);
String md5 = null;
try {
System.out.println("播放歌曲变换:" + metadata.getString("md5"));
md5 = metadata.getString("md5");
} catch (Exception ignored) {
}
if (md5 != null) {
setPlayData(MusicContainer.getLibs().findMusic(md5, MusicContainer.getInstance().getPlayList()));
}
}
@Override
public void onSessionDestroyed() {
super.onSessionDestroyed();
System.out.println("连接被销毁");
}
@Override
public void onQueueChanged(List<MediaSessionCompat.QueueItem> queue) {
super.onQueueChanged(queue);
System.out.println("不知道是啥变换了");
}
public void setImage() {
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -34,6 +34,7 @@
android:layout_marginTop="150dp" android:layout_marginTop="150dp"
android:contentDescription="专辑图" android:contentDescription="专辑图"
android:src="@drawable/ic_launcher_foreground" android:src="@drawable/ic_launcher_foreground"
android:transitionName="album_image"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
@ -43,13 +44,14 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="26dp" android:layout_marginBottom="26dp"
android:shadowColor="@color/textColorGray" android:shadowColor="@color/colorBlack"
android:shadowDx="5" android:shadowDx="5"
android:shadowDy="5" android:shadowDy="5"
android:shadowRadius="1" android:shadowRadius="1"
android:text="title" android:text="title"
android:textColor="@color/musicTitle" android:textColor="@color/musicTitle"
android:textSize="24sp" android:textSize="24sp"
android:transitionName="title"
app:layout_constraintBottom_toTopOf="@+id/album_image" app:layout_constraintBottom_toTopOf="@+id/album_image"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
@ -76,6 +78,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_weight="1" android:layout_weight="1"
android:shadowColor="@color/colorBlack"
android:shadowDx="5"
android:shadowDy="5"
android:shadowRadius="1"
android:text="00:00" android:text="00:00"
android:textColor="@color/textColorWhite" /> android:textColor="@color/textColorWhite" />
@ -85,8 +91,12 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:gravity="center" android:gravity="center"
android:textColor="@color/textColorWhite" android:shadowColor="@color/colorBlack"
android:text="TextView" /> android:shadowDx="5"
android:shadowDy="5"
android:shadowRadius="1"
android:text="TextView"
android:textColor="@color/textColorWhite" />
<TextView <TextView
android:id="@+id/durationTime" android:id="@+id/durationTime"
@ -95,6 +105,10 @@
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:layout_weight="1" android:layout_weight="1"
android:gravity="end" android:gravity="end"
android:shadowColor="@color/colorBlack"
android:shadowDx="5"
android:shadowDy="5"
android:shadowRadius="1"
android:text="00:00" android:text="00:00"
android:textColor="@color/textColorGray" /> android:textColor="@color/textColorGray" />
</LinearLayout> </LinearLayout>
@ -125,20 +139,30 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"> app:layout_constraintStart_toStartOf="parent">
<ImageButton
android:id="@+id/playModel"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="30dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_play_random" />
<ImageButton <ImageButton
android:id="@+id/previous" android:id="@+id/previous"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginEnd="30dp" android:layout_marginEnd="30dp"
android:src="@android:drawable/ic_media_previous" /> android:src="@android:drawable/ic_media_previous"
android:transitionName="previous" />
<ImageButton <ImageButton
android:id="@+id/play" android:id="@+id/play"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:src="@android:drawable/ic_media_play" /> android:src="@android:drawable/ic_media_play"
android:transitionName="play" />
<ImageButton <ImageButton
android:id="@+id/next" android:id="@+id/next"
@ -146,7 +170,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginStart="30dp" android:layout_marginStart="30dp"
android:src="@android:drawable/ic_media_next" /> android:layout_marginEnd="80dp"
android:src="@android:drawable/ic_media_next"
android:transitionName="next" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -163,6 +189,9 @@
android:id="@+id/album" android:id="@+id/album"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:shadowColor="@color/colorBlack"
android:shadowDx="5"
android:shadowDy="5"
android:shadowRadius="1" android:shadowRadius="1"
android:text="album" android:text="album"
android:textColor="@color/textColorWhite" android:textColor="@color/textColorWhite"
@ -172,9 +201,14 @@
android:id="@+id/artist" android:id="@+id/artist"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:shadowColor="@color/colorBlack"
android:shadowDx="5"
android:shadowDy="5"
android:shadowRadius="1"
android:text="artist" android:text="artist"
android:textColor="@color/textColorWhite" android:textColor="@color/textColorWhite"
android:textSize="20sp" /> android:textSize="20sp"
android:transitionName="artist" />
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/include"
layout="@layout/layout_play"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.ogaclejapan.smarttablayout.SmartTabLayout
android:id="@+id/viewpagertab"
android:layout_width="match_parent"
android:layout_height="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/include"
app:stl_clickable="true"
app:stl_defaultTabBackground="?attr/selectableItemBackground"
app:stl_defaultTabTextAllCaps="true"
app:stl_defaultTabTextColor="#FC000000"
app:stl_defaultTabTextHorizontalPadding="16dp"
app:stl_defaultTabTextMinWidth="0dp"
app:stl_defaultTabTextSize="12sp"
app:stl_distributeEvenly="false"
app:stl_dividerColor="#4D000000"
app:stl_dividerThickness="1dp"
app:stl_drawDecorationAfterTab="false"
app:stl_indicatorAlwaysInCenter="false"
app:stl_indicatorColor="#40C4FF"
app:stl_indicatorCornerRadius="2dp"
app:stl_indicatorGravity="bottom"
app:stl_indicatorInFront="false"
app:stl_indicatorInterpolation="smart"
app:stl_indicatorThickness="4dp"
app:stl_indicatorWidth="auto"
app:stl_indicatorWithoutPadding="false"
app:stl_overlineColor="#4D000000"
app:stl_overlineThickness="0dp"
app:stl_titleOffset="24dp"
app:stl_underlineColor="#4D000000"
app:stl_underlineThickness="1dp" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="@id/viewpagertab"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/viewpagertab" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/album_image"
android:layout_width="64dp"
android:layout_height="64dp"
android:transitionName="album_image"
app:srcCompat="@mipmap/ic_launcher" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<cc.ibooker.ztextviewlib.MarqueeTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:shadowColor="@color/textColorGray"
android:shadowDx="5"
android:shadowDy="5"
android:shadowRadius="1"
android:text="TextView"
android:textColor="@color/colorBlack"
android:transitionName="title" />
<cc.ibooker.ztextviewlib.MarqueeTextView
android:id="@+id/artist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:shadowColor="@color/textColorGray"
android:shadowDx="5"
android:shadowDy="5"
android:shadowRadius="1"
android:text="TextView"
android:textColor="@color/colorBlack"
android:transitionName="artist" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:gravity="end"
android:orientation="horizontal">
<ImageButton
android:id="@+id/previous"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:transitionName="previous"
app:srcCompat="@android:drawable/ic_media_previous" />
<ImageButton
android:id="@+id/play"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:transitionName="play"
app:srcCompat="@android:drawable/ic_media_play" />
<ImageButton
android:id="@+id/next"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_marginEnd="10dp"
android:scaleType="fitCenter"
android:transitionName="next"
app:srcCompat="@android:drawable/ic_media_next" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -5,7 +5,7 @@
<color name="colorAccent">#03DAC5</color> <color name="colorAccent">#03DAC5</color>
<color name="colorBlack">#000000</color> <color name="colorBlack">#000000</color>
<color name="musicTitle">#000000</color> <color name="musicTitle">#FFFFFF</color>
<color name="musicArtist">#000000</color> <color name="musicArtist">#000000</color>
<color name="textColorGray">#DEDEDE</color> <color name="textColorGray">#DEDEDE</color>
<color name="textColorWhite">#FFFFFF</color> <color name="textColorWhite">#FFFFFF</color>