package me.wcy.music.application; import android.app.Application; import android.content.Intent; import me.wcy.music.service.PlayService; import me.wcy.music.storage.db.DBManager; /** * 自定义Application * Created by wcy on 2015/11/27. */ public class MusicApplication extends Application { @Override public void onCreate() { super.onCreate(); AppCache.get().init(this); ForegroundObserver.init(this); DBManager.get().init(this); Intent intent = new Intent(this, PlayService.class); startService(intent); } }
package me.wcy.music.application; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.support.v4.app.NotificationCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.RemoteViews; import android.widget.TextView; import java.util.ArrayList; import java.util.List; import me.wcy.music.R; import me.wcy.music.activity.MusicActivity; import me.wcy.music.constants.Extras; import me.wcy.music.model.Music; import me.wcy.music.receiver.StatusBarReceiver; import me.wcy.music.service.PlayService; import me.wcy.music.utils.CoverLoader; import me.wcy.music.utils.FileUtils; /** * Created by wcy on 2017/4/18. */ public class Notifier { private static final int NOTIFICATION_ID = 0x111; private PlayService playService; private NotificationManager notificationManager; public static Notifier get() { return SingletonHolder.instance; } private static class SingletonHolder { private static Notifier instance = new Notifier(); } private Notifier() { } public void init(PlayService playService) { this.playService = playService; notificationManager = (NotificationManager) playService.getSystemService(Context.NOTIFICATION_SERVICE); } public void showPlay(Music music) { if (music == null) { return; } playService.startForeground(NOTIFICATION_ID, buildNotification(playService, music, true)); } public void showPause(Music music) { if (music == null) { return; } playService.stopForeground(false); notificationManager.notify(NOTIFICATION_ID, buildNotification(playService, music, false)); } public void cancelAll() { notificationManager.cancelAll(); } private Notification buildNotification(Context context, Music music, boolean isPlaying) { Intent intent = new Intent(context, MusicActivity.class); intent.putExtra(Extras.EXTRA_NOTIFICATION, true); intent.setAction(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setContentIntent(pendingIntent) .setSmallIcon(R.drawable.ic_notification) .setCustomContentView(getRemoteViews(context, music, isPlaying)); return builder.build(); } private RemoteViews getRemoteViews(Context context, Music music, boolean isPlaying) { String title = music.getTitle(); String subtitle = FileUtils.getArtistAndAlbum(music.getArtist(), music.getAlbum()); Bitmap cover = CoverLoader.get().loadThumb(music); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification); if (cover != null) { remoteViews.setImageViewBitmap(R.id.iv_icon, cover); } else { remoteViews.setImageViewResource(R.id.iv_icon, R.drawable.ic_launcher); } remoteViews.setTextViewText(R.id.tv_title, title); remoteViews.setTextViewText(R.id.tv_subtitle, subtitle); boolean isLightNotificationTheme = isLightNotificationTheme(playService); Intent playIntent = new Intent(StatusBarReceiver.ACTION_STATUS_BAR); playIntent.putExtra(StatusBarReceiver.EXTRA, StatusBarReceiver.EXTRA_PLAY_PAUSE); PendingIntent playPendingIntent = PendingIntent.getBroadcast(context, 0, playIntent, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setImageViewResource(R.id.iv_play_pause, getPlayIconRes(isLightNotificationTheme, isPlaying)); remoteViews.setOnClickPendingIntent(R.id.iv_play_pause, playPendingIntent); Intent nextIntent = new Intent(StatusBarReceiver.ACTION_STATUS_BAR); nextIntent.putExtra(StatusBarReceiver.EXTRA, StatusBarReceiver.EXTRA_NEXT); PendingIntent nextPendingIntent = PendingIntent.getBroadcast(context, 1, nextIntent, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setImageViewResource(R.id.iv_next, getNextIconRes(isLightNotificationTheme)); remoteViews.setOnClickPendingIntent(R.id.iv_next, nextPendingIntent); return remoteViews; } private int getPlayIconRes(boolean isLightNotificationTheme, boolean isPlaying) { if (isPlaying) { return isLightNotificationTheme ? R.drawable.ic_status_bar_pause_dark_selector : R.drawable.ic_status_bar_pause_light_selector; } else { return isLightNotificationTheme ? R.drawable.ic_status_bar_play_dark_selector : R.drawable.ic_status_bar_play_light_selector; } } private int getNextIconRes(boolean isLightNotificationTheme) { return isLightNotificationTheme ? R.drawable.ic_status_bar_next_dark_selector : R.drawable.ic_status_bar_next_light_selector; } private boolean isLightNotificationTheme(Context context) { int notificationTextColor = getNotificationTextColor(context); return isSimilarColor(Color.BLACK, notificationTextColor); } private int getNotificationTextColor(Context context) { NotificationCompat.Builder builder = new NotificationCompat.Builder(context); Notification notification = builder.build(); RemoteViews remoteViews = notification.contentView; if (remoteViews == null) { return Color.BLACK; } int layoutId = remoteViews.getLayoutId(); ViewGroup notificationLayout = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null); TextView title = notificationLayout.findViewById(android.R.id.title); if (title != null) { return title.getCurrentTextColor(); } else { return findTextColor(notificationLayout); } } /** * 如果通过 android.R.id.title 无法获得 title , * 则通过遍历 notification 布局找到 textSize 最大的 TextView ,应该就是 title 了。 */ private int findTextColor(ViewGroup notificationLayout) { List<TextView> textViewList = new ArrayList<>(); findTextView(notificationLayout, textViewList); float maxTextSize = -1; TextView maxTextView = null; for (TextView textView : textViewList) { if (textView.getTextSize() > maxTextSize) { maxTextView = textView; } } if (maxTextView != null) { return maxTextView.getCurrentTextColor(); } return Color.BLACK; } private void findTextView(View view, List<TextView> textViewList) { if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; for (int i = 0; i < viewGroup.getChildCount(); i++) { findTextView(viewGroup.getChildAt(i), textViewList); } } else if (view instanceof TextView) { textViewList.add((TextView) view); } } private boolean isSimilarColor(int baseColor, int color) { int simpleBaseColor = baseColor | 0xff000000; int simpleColor = color | 0xff000000; int baseRed = Color.red(simpleBaseColor) - Color.red(simpleColor); int baseGreen = Color.green(simpleBaseColor) - Color.green(simpleColor); int baseBlue = Color.blue(simpleBaseColor) - Color.blue(simpleColor); double value = Math.sqrt(baseRed * baseRed + baseGreen * baseGreen + baseBlue * baseBlue); return value < 180.0; } }
package me.wcy.music.http; public abstract class HttpCallback<T> { public abstract void onSuccess(T t); public abstract void onFail(Exception e); public void onFinish() { } }
package me.wcy.music.http; import android.graphics.Bitmap; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.zhy.http.okhttp.OkHttpUtils; import com.zhy.http.okhttp.callback.BitmapCallback; import com.zhy.http.okhttp.callback.FileCallBack; import java.io.File; import java.util.concurrent.TimeUnit; import me.wcy.music.model.ArtistInfo; import me.wcy.music.model.DownloadInfo; import me.wcy.music.model.Lrc; import me.wcy.music.model.OnlineMusicList; import me.wcy.music.model.SearchMusic; import me.wcy.music.model.Splash; import okhttp3.Call; import okhttp3.OkHttpClient; public class HttpClient { private static final String SPLASH_URL = "http://localhost:8080"; private static final String BASE_URL = "http://music.163.com/song/media/outer/"; private static final String METHOD_GET_MUSIC_LIST = "baidu.ting.billboard.billList"; private static final String METHOD_DOWNLOAD_MUSIC = "baidu.ting.song.play"; private static final String METHOD_ARTIST_INFO = "baidu.ting.artist.getInfo"; private static final String METHOD_SEARCH_MUSIC = "baidu.ting.search.catalogSug"; private static final String METHOD_LRC = "baidu.ting.song.lry"; private static final String PARAM_METHOD = "method"; private static final String PARAM_TYPE = "type"; private static final String PARAM_SIZE = "size"; private static final String PARAM_OFFSET = "offset"; private static final String PARAM_SONG_ID = "songid"; private static final String PARAM_TING_UID = "tinguid"; private static final String PARAM_QUERY = "query"; static { OkHttpClient okHttpClient = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .addInterceptor(new HttpInterceptor()) .build(); OkHttpUtils.initClient(okHttpClient); } public static void getSplash(@NonNull final HttpCallback<Splash> callback) { OkHttpUtils.get().url(SPLASH_URL).build() .execute(new JsonCallback<Splash>(Splash.class) { @Override public void onResponse(Splash response, int id) { callback.onSuccess(response); } @Override public void onError(Call call, Exception e, int id) { callback.onFail(e); } @Override public void onAfter(int id) { callback.onFinish(); } }); } public static void downloadFile(String url, String destFileDir, String destFileName, @Nullable final HttpCallback<File> callback) { OkHttpUtils.get().url(url).build() .execute(new FileCallBack(destFileDir, destFileName) { @Override public void inProgress(float progress, long total, int id) { } @Override public void onResponse(File file, int id) { if (callback != null) { callback.onSuccess(file); } } @Override public void onError(Call call, Exception e, int id) { if (callback != null) { callback.onFail(e); } } @Override public void onAfter(int id) { if (callback != null) { callback.onFinish(); } } }); } public static void getSongListInfo(String type, int size, int offset, @NonNull final HttpCallback<OnlineMusicList> callback) { OkHttpUtils.get().url(BASE_URL) .addParams(PARAM_METHOD, METHOD_GET_MUSIC_LIST) .addParams(PARAM_TYPE, type) .addParams(PARAM_SIZE, String.valueOf(size)) .addParams(PARAM_OFFSET, String.valueOf(offset)) .build() .execute(new JsonCallback<OnlineMusicList>(OnlineMusicList.class) { @Override public void onResponse(OnlineMusicList response, int id) { callback.onSuccess(response); } @Override public void onError(Call call, Exception e, int id) { callback.onFail(e); } @Override public void onAfter(int id) { callback.onFinish(); } }); } public static void getMusicDownloadInfo(String songId, @NonNull final HttpCallback<DownloadInfo> callback) { OkHttpUtils.get().url(BASE_URL) .addParams(PARAM_METHOD, METHOD_DOWNLOAD_MUSIC) .addParams(PARAM_SONG_ID, songId) .build() .execute(new JsonCallback<DownloadInfo>(DownloadInfo.class) { @Override public void onResponse(DownloadInfo response, int id) { callback.onSuccess(response); } @Override public void onError(Call call, Exception e, int id) { callback.onFail(e); } @Override public void onAfter(int id) { callback.onFinish(); } }); } public static void getBitmap(String url, @NonNull final HttpCallback<Bitmap> callback) { OkHttpUtils.get().url(url).build() .execute(new BitmapCallback() { @Override public void onResponse(Bitmap bitmap, int id) { callback.onSuccess(bitmap); } @Override public void onError(Call call, Exception e, int id) { callback.onFail(e); } @Override public void onAfter(int id) { callback.onFinish(); } }); } public static void getLrc(String songId, @NonNull final HttpCallback<Lrc> callback) { OkHttpUtils.get().url(BASE_URL) .addParams(PARAM_METHOD, METHOD_LRC) .addParams(PARAM_SONG_ID, songId) .build() .execute(new JsonCallback<Lrc>(Lrc.class) { @Override public void onResponse(Lrc response, int id) { callback.onSuccess(response); } @Override public void onError(Call call, Exception e, int id) { callback.onFail(e); } @Override public void onAfter(int id) { callback.onFinish(); } }); } public static void searchMusic(String keyword, @NonNull final HttpCallback<SearchMusic> callback) { OkHttpUtils.get().url(BASE_URL) .addParams(PARAM_METHOD, METHOD_SEARCH_MUSIC) .addParams(PARAM_QUERY, keyword) .build() .execute(new JsonCallback<SearchMusic>(SearchMusic.class) { @Override public void onResponse(SearchMusic response, int id) { callback.onSuccess(response); } @Override public void onError(Call call, Exception e, int id) { callback.onFail(e); } @Override public void onAfter(int id) { callback.onFinish(); } }); } public static void getArtistInfo(String tingUid, @NonNull final HttpCallback<ArtistInfo> callback) { OkHttpUtils.get().url(BASE_URL) .addParams(PARAM_METHOD, METHOD_ARTIST_INFO) .addParams(PARAM_TING_UID, tingUid) .build() .execute(new JsonCallback<ArtistInfo>(ArtistInfo.class) { @Override public void onResponse(ArtistInfo response, int id) { callback.onSuccess(response); } @Override public void onError(Call call, Exception e, int id) { callback.onFail(e); } @Override public void onAfter(int id) { callback.onFinish(); } }); } }