com.massivcode.androidmusicplayer.services.MusicService.java Source code

Java tutorial

Introduction

Here is the source code for com.massivcode.androidmusicplayer.services.MusicService.java

Source

/*
 * Copyright 2015. Pureum Choe
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.massivcode.androidmusicplayer.services;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v7.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

import com.massivcode.androidmusicplayer.R;
import com.massivcode.androidmusicplayer.activities.MainActivity;
import com.massivcode.androidmusicplayer.events.Event;
import com.massivcode.androidmusicplayer.events.FinishActivity;
import com.massivcode.androidmusicplayer.events.InitEvent;
import com.massivcode.androidmusicplayer.events.MusicEvent;
import com.massivcode.androidmusicplayer.events.PlayBack;
import com.massivcode.androidmusicplayer.events.RequestEvent;
import com.massivcode.androidmusicplayer.events.RequestMusicEvent;
import com.massivcode.androidmusicplayer.events.Restore;
import com.massivcode.androidmusicplayer.events.SaveState;
import com.massivcode.androidmusicplayer.models.MusicInfo;
import com.massivcode.androidmusicplayer.receiver.UnPlugReceiver;
import com.massivcode.androidmusicplayer.utils.DataBackupUtil;
import com.massivcode.androidmusicplayer.utils.MusicInfoLoadUtil;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import de.greenrobot.event.EventBus;

public class MusicService extends Service implements MediaPlayer.OnCompletionListener {
    private static final String TAG = MusicService.class.getSimpleName();

    public static final String ACTION_PLAY = "ACTION_PLAY";
    public static final String ACTION_PLAY_NEXT = "ACTION_PLAY_NEXT";
    public static final String ACTION_PLAY_PREVIOUS = "ACTION_PLAY_PREVIOUS";
    public static final String ACTION_PAUSE = "ACTION_PAUSE";
    public static final String ACTION_PAUSE_UNPLUGGED = "ACTION_PAUSE_UNPLUGGED";
    public static final String ACTION_PLAY_SELECTED = "ACTION_PLAY_SELECTED";
    public static final String ACTION_FINISH = "ACTION_FINISH";

    private boolean isReady = false;
    private MediaSessionCompat mSession;
    private MediaMetadataCompat mMetadata;

    private SaveState mSaveState;

    //  
    private static class UiRefresher extends Handler {
        private final WeakReference<MusicService> mService;

        UiRefresher(MusicService service) {
            mService = new WeakReference<MusicService>(service);
        }

        @Override
        public void handleMessage(Message msg) {
            MusicService service = mService.get();
            if (service != null) {
                service.sendEvents();
            }
        }
    }

    UiRefresher mHandler = new UiRefresher(this);

    private final IBinder mBinder = new LocalBinder();

    @Override
    public void onCompletion(MediaPlayer mp) {

        //   ?? ???  ? 

        mp.pause();
        mp.reset();

        try {
            // ? ? ?? ?? .
            boolean isShuffle = DataBackupUtil.getInstance(getApplicationContext()).loadIsShuffle();
            //  ? ?.
            boolean isRepeat = DataBackupUtil.getInstance(getApplicationContext()).loadIsRepeat();
            Log.d(TAG, " ->  : " + isShuffle + "  : " + isRepeat);

            if (mCurrentPlaylist != null) {
                setNextMusicInfo(mp, isShuffle, isRepeat);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (mCurrentMusicInfo != null) {
                showNotification();
                sendMusicEvent();
            }
        }

    }

    private void setNextMusicInfo(MediaPlayer mp, boolean isShuffle, boolean isRepeat) throws IOException {

        if (isShuffle) {
            mCurrentPosition = shuffle(mCurrentPlaylist.size());
        } else {
            if (mCurrentPosition < getCurrentPlaylistSize()) {
                mCurrentPosition++;
            } else {
                mCurrentPosition = 0;
            }
        }

        mp.setDataSource(getApplicationContext(), switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
        mCurrentMusicInfo = MusicInfoLoadUtil.getSelectedMusicInfo(getApplicationContext(),
                mCurrentPlaylist.get(mCurrentPosition));

        if (isShuffle) {
            mp.prepare();
            mp.start();
            isReady = true;
        } else {
            if (isRepeat) {
                mp.prepare();
                mp.start();
                isReady = true;
            } else {
                if (mCurrentPosition != 0) {
                    mp.prepare();
                    mp.start();
                    isReady = true;
                } else {
                    mp.stop();
                    mp.reset();
                    isReady = false;
                }
            }
        }
    }

    public class LocalBinder extends Binder {
        public MusicService getService() {
            // Return this instance of LocalService so clients can call public methods
            return MusicService.this;
        }
    }

    private MediaPlayer mMediaPlayer;
    private String mAction = null;
    private ArrayList<Long> mCurrentPlaylist;
    private int mCurrentPosition = -1;
    private MusicInfo mCurrentMusicInfo;
    private UnPlugReceiver mUnPlugReceiver;

    private HashMap<Long, MusicInfo> mAllMusicData = null;

    @Override
    public void onCreate() {
        super.onCreate();

        Log.d(TAG, "MusicService.onCreate()");
        Log.d(TAG, " : " + DataBackupUtil.getInstance(getApplicationContext()).loadIsShuffle() + "  : "
                + DataBackupUtil.getInstance(getApplicationContext()).loadIsRepeat());

        // EventBus ?? ?  ?  
        EventBus.getDefault().register(this);

        mMediaPlayer = new MediaPlayer();

        mMediaPlayer.setOnCompletionListener(this);

        mUnPlugReceiver = new UnPlugReceiver();
        IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
        registerReceiver(mUnPlugReceiver, filter);

        if (Build.VERSION.SDK_INT < 23) {
            if (mAllMusicData == null) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d(TAG, "InitEvent @ service");
                        mAllMusicData = MusicInfoLoadUtil.getAllMusicInfo(getApplicationContext());
                    }
                }).start();
            }
        }

        int loadedPosition = DataBackupUtil.getInstance(getApplicationContext()).loadCurrentPlayingMusicPosition();
        if (loadedPosition != -1) {
            mCurrentPosition = loadedPosition;
            Log.d(TAG, " ?  : " + loadedPosition);
        }

        ArrayList<Long> loadedPlaylist = DataBackupUtil.getInstance(getApplicationContext()).loadLastPlayedSongs();
        if (loadedPlaylist != null && loadedPlaylist.size() != 0) {
            mCurrentPlaylist = loadedPlaylist;
            mCurrentMusicInfo = MusicInfoLoadUtil.getSelectedMusicInfo(getApplicationContext(),
                    mCurrentPlaylist.get(mCurrentPosition));
            try {
                mMediaPlayer.setDataSource(getApplicationContext(),
                        switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                mMediaPlayer.prepare();
            } catch (IOException e) {
                e.printStackTrace();
            }
            isReady = true;
            // TODO ?  
            sendAllEvent();
            EventBus.getDefault().post(new RequestEvent());
        }

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent != null && intent.getAction() != null) {
            mAction = intent.getAction();
        }

        if (mAction == null) {
            EventBus.getDefault().post(new FinishActivity());
            stopForeground(true);
            stopService(new Intent(getApplicationContext(), MusicService.class));
            return START_NOT_STICKY;
        }

        switch (mAction) {
        case ACTION_PLAY_SELECTED:
            mCurrentPosition = intent != null ? intent.getIntExtra("position", 0) : 0;
            mCurrentMusicInfo = MusicInfoLoadUtil.getSelectedMusicInfo(getApplicationContext(),
                    mCurrentPlaylist.get(mCurrentPosition));
            break;
        case ACTION_PLAY:
            mCurrentPlaylist = (ArrayList<Long>) (intent != null ? intent.getSerializableExtra("list") : null);
            mCurrentPosition = intent.getIntExtra("position", 0);
            mCurrentMusicInfo = MusicInfoLoadUtil.getSelectedMusicInfo(getApplicationContext(),
                    mCurrentPlaylist.get(mCurrentPosition));
            break;
        case ACTION_PLAY_NEXT:
        case ACTION_PLAY_PREVIOUS:
            boolean isShuffle = DataBackupUtil.getInstance(getApplicationContext()).loadIsShuffle();
            if (isShuffle) {
                mCurrentPosition = shuffle(mCurrentPlaylist.size());
            } else {
                mCurrentPosition = intent != null ? intent.getIntExtra("position", 0) : 0;
            }
            mCurrentMusicInfo = MusicInfoLoadUtil.getSelectedMusicInfo(getApplicationContext(),
                    mCurrentPlaylist.get(mCurrentPosition));
            break;
        case ACTION_FINISH:

            if (mMediaPlayer.isPlaying()) {
                mHandler.removeMessages(0);
                mMediaPlayer.stop();
                mMediaPlayer.release();
                mMediaPlayer = null;
            } else {
                mHandler.removeMessages(0);
                mMediaPlayer.release();
                mMediaPlayer = null;
            }
            EventBus.getDefault().post(new FinishActivity());
            stopForeground(true);
            stopService(new Intent(getApplicationContext(), MusicService.class));
            break;
        case ACTION_PAUSE_UNPLUGGED:
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                if (mCurrentMusicInfo != null && mCurrentPlaylist != null) {
                    sendAllEvent();
                    showNotification();
                }
            }
            break;
        }

        switch (mAction) {

        case ACTION_PLAY_SELECTED:

            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                mMediaPlayer.reset();
                try {

                    mMediaPlayer.setDataSource(getApplicationContext(),
                            switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                    mMediaPlayer.prepare();
                    isReady = true;

                    // TODO ?  
                    sendAllEvent();

                    mMediaPlayer.start();

                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    showNotification();
                }
            } else {
                mMediaPlayer.reset();
                try {
                    mMediaPlayer.setDataSource(getApplicationContext(),
                            switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                    mMediaPlayer.prepare();
                    isReady = true;
                    // TODO ?  
                    sendAllEvent();

                    mMediaPlayer.start();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    showNotification();
                }
            }
            break;
        case ACTION_PLAY:

            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                mMediaPlayer.reset();
                try {
                    mMediaPlayer.setDataSource(getApplicationContext(),
                            switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                    mMediaPlayer.prepare();
                    isReady = true;

                    // TODO ?  
                    sendAllEvent();

                    mMediaPlayer.start();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    showNotification();
                }
            } else {
                mMediaPlayer.reset();
                try {
                    mMediaPlayer.setDataSource(getApplicationContext(),
                            switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                    mMediaPlayer.prepare();
                    isReady = true;
                    // TODO ?  
                    sendAllEvent();

                    mMediaPlayer.start();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    showNotification();
                }
            }
            break;
        case ACTION_PAUSE:
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
            } else {
                mMediaPlayer.start();
            }
            if (mCurrentMusicInfo != null && mCurrentPlaylist != null) {
                sendAllEvent();
                showNotification();
            }
            break;
        case ACTION_PLAY_NEXT:
            //                Log.d(TAG, "ACTION_PLAY_NEXT");
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.stop();
                mMediaPlayer.reset();
                try {
                    mMediaPlayer.setDataSource(getApplicationContext(),
                            switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                    mMediaPlayer.prepare();
                    isReady = true;
                    // TODO ?  
                    sendAllEvent();

                    mMediaPlayer.start();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    showNotification();
                }

            } else {
                mMediaPlayer.reset();
                try {
                    mMediaPlayer.setDataSource(getApplicationContext(),
                            switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                    mMediaPlayer.prepare();
                    isReady = true;
                    // TODO ?  
                    sendAllEvent();

                    mMediaPlayer.start();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    showNotification();
                }
            }

            break;
        case ACTION_PLAY_PREVIOUS:
            if (mMediaPlayer.isPlaying()) {

                mMediaPlayer.stop();
                mMediaPlayer.reset();
                try {
                    mMediaPlayer.setDataSource(getApplicationContext(),
                            switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                    mMediaPlayer.prepare();
                    isReady = true;
                    // TODO ?  
                    sendAllEvent();
                    mMediaPlayer.start();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    showNotification();
                }

            } else {
                mMediaPlayer.reset();
                try {
                    mMediaPlayer.setDataSource(getApplicationContext(),
                            switchIdToUri(mCurrentPlaylist.get(mCurrentPosition)));
                    mMediaPlayer.prepare();
                    isReady = true;
                    // TODO ?  
                    sendAllEvent();
                    mMediaPlayer.start();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    showNotification();
                }
            }
            break;
        }

        return START_STICKY;
    }

    private void setMetaData() {
        if (mCurrentMusicInfo != null) {
            Bitmap bitmap = MusicInfoLoadUtil.getBitmap(getApplicationContext(), mCurrentMusicInfo.getUri(), 4);
            mMetadata = new MediaMetadataCompat.Builder()
                    .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
                    .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, mCurrentMusicInfo.getArtist())
                    .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, mCurrentMusicInfo.getAlbum())
                    .putString(MediaMetadataCompat.METADATA_KEY_TITLE, mCurrentMusicInfo.getTitle()).build();
            if (mSession == null) {
                mSession = new MediaSessionCompat(this, "tag", null, null);
                mSession.setMetadata(mMetadata);
                mSession.setActive(true);
                mSession.setCallback(new MediaSessionCompat.Callback() {
                    @Override
                    public void onPlay() {
                        super.onPlay();
                        Toast.makeText(MusicService.this, "onPlay", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mMediaPlayer != null) {
            mMediaPlayer.release();
        }
        mMediaPlayer = null;

        unregisterReceiver(mUnPlugReceiver);

        //   
        EventBus.getDefault().unregister(this);

        if (mCurrentPlaylist != null && mCurrentPosition != -1) {
            DataBackupUtil.getInstance(getApplicationContext()).saveCurrentPlayingMusicPosition(mCurrentPosition);
            DataBackupUtil.getInstance(getApplicationContext()).saveCurrentPlaylist(mCurrentPlaylist);
        }

        Log.d(TAG, "MusicService.onDestroy()");

    }

    // EventBus  ? 
    public void onEvent(Event event) {
        if (event instanceof RequestEvent) {
            sendMusicEvent();
            sendPlayback();
        } else if (event instanceof SaveState) {
            mSaveState = new SaveState();
            MusicInfo musicInfo = getCurrentInfo();
            ArrayList<Long> currentPlaylist = getCurrentPlaylist();
            int currentPlayPosition = getCurrentPosition();
            mSaveState.setMusicInfo(musicInfo);
            mSaveState.setCurrentPlaylist(currentPlaylist);
            mSaveState.setCurrentPositionAtPlaylist(currentPlayPosition);
            mSaveState.setCurrentPlayTime(mMediaPlayer.getCurrentPosition());
        } else if (event instanceof Restore) {
            if (mSaveState != null) {
                EventBus.getDefault().post(mSaveState);
            }
        } else if (event instanceof InitEvent) {
            if (mAllMusicData == null) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d(TAG, "InitEvent @ service");
                        mAllMusicData = MusicInfoLoadUtil.getAllMusicInfo(getApplicationContext());
                    }
                }).start();
            }

        } else if (event instanceof RequestMusicEvent) {
            sendMusicEvent();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    public MediaPlayer getMediaPlayer() {
        if (mMediaPlayer != null) {
            return mMediaPlayer;
        } else {
            return null;
        }
    }

    public MusicInfo getCurrentInfo() {
        if (mCurrentPlaylist != null) {
            return MusicInfoLoadUtil.getSelectedMusicInfo(getApplicationContext(),
                    mCurrentPlaylist.get(mCurrentPosition));
        } else {
            return null;
        }

    }

    public boolean isReady() {
        return isReady;
    }

    public int getCurrentPosition() {
        return mCurrentPosition;
    }

    public int getCurrentPlaylistSize() {
        //          = ?? ? : ? 
        return mCurrentPlaylist != null ? (mCurrentPlaylist.size() - 1) : 0;
    }

    private Uri switchIdToUri(long id) {
        return Uri.parse("content://media/external/audio/media/" + id);
    }

    private void sendPlayback() {
        PlayBack playback = new PlayBack();
        playback.setCurrentTime(mMediaPlayer.getCurrentPosition());
        playback.setPlaying(mMediaPlayer.isPlaying());
        EventBus.getDefault().post(playback);
    }

    private void sendMusicEvent() {
        MusicEvent musicEvent = new MusicEvent();
        musicEvent.setMediaPlayer(getMediaPlayer());
        musicEvent.setMusicInfo(getCurrentInfo());
        EventBus.getDefault().post(musicEvent);
    }

    private void sendAllEvent() {
        sendMusicEvent();
        mHandler.sendEmptyMessage(0);
    }

    public ArrayList<Long> getCurrentPlaylist() {
        return mCurrentPlaylist;
    }

    public HashMap<Long, MusicInfo> getAllMusicData() {
        return mAllMusicData;
    }

    private void sendEvents() {
        if (mMediaPlayer.isPlaying()) {
            //            Log.d(TAG, "UIRefresher is running");
            PlayBack playback = new PlayBack();
            playback.setPlaying(mMediaPlayer.isPlaying());
            playback.setCurrentTime(mMediaPlayer.getCurrentPosition());
            EventBus.getDefault().post(playback);

            mHandler.sendEmptyMessageDelayed(0, 1000);

        } else {
            //            Log.d(TAG, "UIRefresher is stopped");
            PlayBack playback = new PlayBack();
            playback.setPlaying(mMediaPlayer.isPlaying());
            playback.setCurrentTime(mMediaPlayer.getCurrentPosition());
            EventBus.getDefault().post(playback);
        }
    }

    private void showNotificationUpperKitKat(MediaMetadataCompat metadata) {
        // Notification 
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
        // Hide the timestamp
        builder.setShowWhen(false);
        // Set the Notification style
        builder.setStyle(new NotificationCompat.MediaStyle().setMediaSession(mSession.getSessionToken())
                .setShowActionsInCompactView(0, 1, 2));
        // Set the Notification color
        builder.setColor(Color.parseColor("#2196F3"));
        // Set the large and small icons
        Bitmap bitmap = MusicInfoLoadUtil.getBitmap(getApplicationContext(), mCurrentMusicInfo.getUri(), 4);
        if (bitmap == null) {
            bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_no_image);
        }
        builder.setLargeIcon(bitmap);
        builder.setSmallIcon(R.mipmap.ic_no_image);
        builder.setContentTitle(mCurrentMusicInfo.getTitle());
        builder.setContentText(mCurrentMusicInfo.getArtist());

        int icon;
        if (mMediaPlayer.isPlaying()) {
            Log.d(TAG, "is playing");
            icon = android.R.drawable.ic_media_pause;
        } else {
            Log.d(TAG, "is not playing");
            icon = android.R.drawable.ic_media_play;
        }

        // ? ? ?   
        // =========================================================================================

        Intent musicPreviousIntent = new Intent(getApplicationContext(), MusicService.class);
        musicPreviousIntent.putExtra("metadata", metadata);
        musicPreviousIntent.setAction(ACTION_PLAY_PREVIOUS);
        musicPreviousIntent.putExtra("position", getPositionAtPreviousOrNext(ACTION_PLAY_PREVIOUS));

        PendingIntent musicPreviousPendingIntent = PendingIntent.getService(getApplicationContext(), 0,
                musicPreviousIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.addAction(android.R.drawable.ic_media_previous, "prev", musicPreviousPendingIntent);
        // =========================================================================================

        // ? ? ?   
        // =========================================================================================
        Intent musicStopIntent = new Intent(getApplicationContext(), MusicService.class);
        musicStopIntent.putExtra("metadata", metadata);
        musicStopIntent.setAction(ACTION_PAUSE);

        PendingIntent musicStopPendingIntent = PendingIntent.getService(getApplicationContext(), 1, musicStopIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        builder.addAction(icon, "pause", musicStopPendingIntent);
        // =========================================================================================

        // ? ? ?   
        // =========================================================================================
        Intent musicNextIntent = new Intent(getApplicationContext(), MusicService.class);
        musicNextIntent.putExtra("metadata", metadata);
        musicNextIntent.setAction(ACTION_PLAY_NEXT);
        musicNextIntent.putExtra("position", getPositionAtPreviousOrNext(ACTION_PLAY_NEXT));

        PendingIntent musicNextPendingIntent = PendingIntent.getService(getApplicationContext(), 2, musicNextIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        builder.addAction(android.R.drawable.ic_media_next, "next", musicNextPendingIntent);
        // =========================================================================================

        //  ? ?   
        // =========================================================================================
        Intent closeIntent = new Intent(getApplicationContext(), MusicService.class);
        closeIntent.setAction(ACTION_FINISH);

        PendingIntent closePendingIntent = PendingIntent.getService(getApplicationContext(), 3, closeIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        builder.addAction(android.R.drawable.arrow_up_float, "close", closePendingIntent);
        // =========================================================================================

        // Notification  ?   PendingIntent 
        // =========================================================================================
        Intent activityStartIntent = new Intent(MainActivity.ACTION_NAME);
        activityStartIntent.putExtra("restore", getCurrentInfo());
        PendingIntent activityStartPendingIntent = PendingIntent.getActivity(getApplicationContext(), 1,
                activityStartIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(activityStartPendingIntent);
        // =========================================================================================

        Notification notification = builder.setAutoCancel(true).build();

        startForeground(1, notification);

    }

    public int getPositionAtPreviousOrNext(String flag) {
        int position = getCurrentPosition();
        switch (flag) {
        case ACTION_PLAY_NEXT:
            if (position < getCurrentPlaylistSize()) {
                position += 1;
            } else {
                position = 0;
            }
            break;
        case ACTION_PLAY_PREVIOUS:
            if (position > 0) {
                position -= 1;
            } else {
                position = getCurrentPlaylistSize();
            }
            break;
        }
        return position;
    }

    /**
     * random.nextInt(range) -> 0 ~ range-1
     *
     * @param range
     * @return
     */
    public int shuffle(int range) {
        int result;

        if (range == 1) {
            return 0;
        }

        Random random = new Random();
        result = random.nextInt(range);

        if (result == mCurrentPosition) {
            result = shuffle(range);
        }

        return result;
    }

    private void showNotificationUnderLollipop() {
        Notification.Builder builder = new Notification.Builder(this);
        RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.notification);

        // ? ? ?   
        // =========================================================================================

        Intent musicPreviousIntent = new Intent(getApplicationContext(), MusicService.class);
        musicPreviousIntent.setAction(ACTION_PLAY_PREVIOUS);
        musicPreviousIntent.putExtra("position", getPositionAtPreviousOrNext(ACTION_PLAY_PREVIOUS));

        PendingIntent musicPreviousPendingIntent = PendingIntent.getService(getApplicationContext(), 0,
                musicPreviousIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.noti_previous_ib, musicPreviousPendingIntent);
        // =========================================================================================

        // ? ? ?   
        // =========================================================================================
        Intent musicStopIntent = new Intent(getApplicationContext(), MusicService.class);
        musicStopIntent.setAction(ACTION_PAUSE);

        PendingIntent musicStopPendingIntent = PendingIntent.getService(getApplicationContext(), 1, musicStopIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.noti_play_ib, musicStopPendingIntent);
        // =========================================================================================

        // ? ? ?   
        // =========================================================================================
        Intent musicNextIntent = new Intent(getApplicationContext(), MusicService.class);
        musicNextIntent.setAction(ACTION_PLAY_NEXT);
        musicNextIntent.putExtra("position", getPositionAtPreviousOrNext(ACTION_PLAY_NEXT));

        PendingIntent musicNextPendingIntent = PendingIntent.getService(getApplicationContext(), 2, musicNextIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.noti_next_ib, musicNextPendingIntent);
        // =========================================================================================

        //  ? ?   
        // =========================================================================================
        Intent closeIntent = new Intent(getApplicationContext(), MusicService.class);
        closeIntent.setAction(ACTION_FINISH);

        PendingIntent closePendingIntent = PendingIntent.getService(getApplicationContext(), 3, closeIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.noti_close_ib, closePendingIntent);
        // =========================================================================================

        // Notification  ?   PendingIntent 
        // =========================================================================================
        Intent activityStartIntent = new Intent(MainActivity.ACTION_NAME);
        activityStartIntent.putExtra("restore", getCurrentInfo());
        PendingIntent activityStartPendingIntent = PendingIntent.getActivity(getApplicationContext(), 1,
                activityStartIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(activityStartPendingIntent);
        // =========================================================================================

        Bitmap bitmap = null;
        if (mCurrentMusicInfo != null) {
            if (mCurrentMusicInfo.getUri() != null) {
                bitmap = MusicInfoLoadUtil.getBitmap(getApplicationContext(), mCurrentMusicInfo.getUri(), 4);
            }
        }
        if (bitmap == null) {
            bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_no_image);
        }

        remoteViews.setImageViewBitmap(R.id.noti_album_art_iv, bitmap);
        if (mCurrentMusicInfo != null) {
            remoteViews.setTextViewText(R.id.noti_artist_tv, mCurrentMusicInfo.getArtist());
            remoteViews.setTextViewText(R.id.noti_title_tv, mCurrentMusicInfo.getTitle());
        }

        builder.setContent(remoteViews);
        builder.setLargeIcon(bitmap);
        builder.setSmallIcon(R.mipmap.ic_no_image);

        if (mMediaPlayer.isPlaying()) {
            remoteViews.setImageViewResource(R.id.noti_play_ib, android.R.drawable.ic_media_pause);
        } else {
            remoteViews.setImageViewResource(R.id.noti_play_ib, android.R.drawable.ic_media_play);
        }

        builder.setAutoCancel(false);

        Notification notification = builder.build();

        startForeground(1, notification);
    }

    private void showNotification() {
        if (Build.VERSION.SDK_INT < 21) {
            showNotificationUnderLollipop();
        } else {
            setMetaData();
            showNotificationUpperKitKat(mMetadata);
        }
    }

}