Android Open Source - unmp Player Service






From Project

Back to project page unmp.

License

The source code is released under:

MIT License

If you think the Android project unmp listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.parnswir.unmp;
//from  ww  w . j  ava2  s .co m
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;

import com.parnswir.unmp.core.AlbumCoverRetriever;
import com.parnswir.unmp.core.C;
import com.parnswir.unmp.core.DatabaseUtils;
import com.parnswir.unmp.core.ImageLoader;
import com.parnswir.unmp.core.NotificationBuilder;
import com.parnswir.unmp.media.MediaPlayerStatus;
import com.parnswir.unmp.playlist.MediaFile;
import com.parnswir.unmp.playlist.Playlist;

public class PlayerService extends Service implements OnAudioFocusChangeListener {
  
  public static final String 
    EXTRA_ID = C.PREFIX + "state",
    EXTRA_STATUS = C.PREFIX + "status",
    STATUS_INTENT = C.PREFIX + "STATUS_INTENT",
    SERVICE_INTENT_BUNDLE = C.PREFIX + "intent_bundle",
    PLAYLIST_ADDITION = C.PREFIX + "addition",
    PLAYLIST_DELETION = C.PREFIX + "deletion",
    FILE_NAME = C.PREFIX + "file_name",
    FROM_PLAYLIST = C.PREFIX + "from_playlist",
    TIME = C.PREFIX + "time";
  
  public static final int 
    STOP = 0,
    START = 1,
    PLAY = 2,
    PLAY_FILE = 3,
    PAUSE = 4,
    NEXT = 5,
    PREVIOUS = 6,
    SET_TIME = 7,
    
    LOAD_PLAYLIST = 10,
    MODIFY_PLAYLIST = 11,
    
    TOGGLE_REPEAT = 20,
    TOGGLE_SHUFFLE = 21,
    
    HIDE_NOTIFICATION = 31,
    
    STATUS = 255;

  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;
  private MediaPlayer player;
  private MediaPlayerStatus status = new MediaPlayerStatus();
  private Playlist playlist;
  
  private NoisyAudioStreamReceiver noisyAudioStreamReceiver = new NoisyAudioStreamReceiver();
  private boolean broadcastIsRegistered = false;
  private boolean showingNotification = false;
  
  private Timer secondsTimer = new Timer(true);
  
  
  public static void setPlayerServiceState(Context context, int state, Bundle bundle) {
    Intent intent = new Intent(context, PlayerService.class);
    intent.putExtra(EXTRA_ID, state);
    if (bundle == null) bundle = new Bundle();
    intent.putExtra(SERVICE_INTENT_BUNDLE, bundle);
    context.startService(intent);
  }
  

  private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
      super(looper);
    }
    
    @Override
    public void handleMessage(Message msg) {
      switch (msg.arg2) {
        case STOP: stop(); stopSelf(msg.arg1); stopForeground(true); break;
        case START: showingNotification = true; showNotification(); break;
        case PLAY: handlePlayBundle(msg.getData()); startPlaylist(); setTime(msg.getData()); break;
        case PAUSE: requestPause(); break;
        case NEXT: next(); break;
        case PREVIOUS: previous(); break;
        case STATUS: broadcastStatus(); break;
        case SET_TIME: setTime(msg.getData()); break;
        case MODIFY_PLAYLIST: modifyPlaylist(msg.getData()); break;
        case TOGGLE_REPEAT: toggleRepeat(); break;
        case TOGGLE_SHUFFLE: toggleShuffle(); break;
        case HIDE_NOTIFICATION: showingNotification = false; stopForeground(true); break;
      }  
    }
  }

  @Override
  public void onCreate() {
    HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_AUDIO);
    thread.start();

    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
    getAudioFocus();
    initializeMediaPlayer();
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    int action = intent.getExtras().getInt(EXTRA_ID);

    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.arg2 = action;
    msg.setData(intent.getBundleExtra(SERVICE_INTENT_BUNDLE));
    mServiceHandler.sendMessage(msg);

    return START_STICKY;
  }

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

  @Override
  public void onDestroy() {
    if (player != null) player.release();
  }
  
  private void showNotification() {
    if (!showingNotification) return;
    
    Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    
    NotificationBuilder builder = NotificationBuilder.getInstance(getApplicationContext());
    builder
      .setSmallIcon(R.drawable.ic_action_play)
      .setLargeIcon(ImageLoader.decodeBitmap(status.cover, ImageLoader.DO_COMPRESS))
      .setOngoing(true)
      .setContentIntent(pendingIntent)
      .setContentTitle(status.title)
      .setContentText(status.artist)
      .addAction(R.drawable.ic_action_play, "Play", pendingIntent)
      .addAction(R.drawable.ic_action_next, "Next", pendingIntent);
    Notification notification = builder.build();

    startForeground(1, notification);
  }
  
  private void getAudioFocus() {
    AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
        AudioManager.AUDIOFOCUS_GAIN);

    if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        // could not get audio focus.
    }
  }
  
  private void initializeMediaPlayer() {
    player = new MediaPlayer();
    player.setAudioStreamType(AudioManager.STREAM_MUSIC);
    player.setOnPreparedListener(new OnPreparedListener() {
      @Override
      public void onPrepared(MediaPlayer arg0) {
        player.start();
        onResume();
      }
    });
    player.setOnErrorListener(new OnErrorListener() {  
      @Override
      public boolean onError(MediaPlayer mp, int error, int extra) {
        return false;
      }
    });
    player.setOnCompletionListener(new OnCompletionListener() {
      @Override
      public void onCompletion(MediaPlayer arg0) {
        next();
      }
    });
  }
  
  private void playFile(String filePath) {
    stop();
    setPlayerDataSource(filePath);
    preparePlayer();
  }
  
  private void startPlaylist() {
    if (playlist == null) return;
    playCurrentFile();
  }
  
  private void handlePlayBundle(Bundle bundle) {
    if (bundle == null) return;
    Playlist source = (Playlist) bundle.getSerializable(FROM_PLAYLIST);
    if (source != null) {
      if (status.playing) stop();
      playlist = source;
      updatePlaylistModifiers();
    }
  }
  
  private void requestPause() {
    if (player.isPlaying()) {
      pause();
    } else if (status.paused) {
      play();
    }
  }
  
  private void play() {
    player.start();
    status.paused = false;
    onResume();
  }
  
  private void pause() {
    unregisterBroadcastReceiver();    
    player.pause();
    onPause();
  }
  
  private void stop() {
    unregisterBroadcastReceiver();
    //if (player.isPlaying()) player.stop();
    player.reset();
    onStop();
  }
  
  private void next() {
    if (status.playing || status.paused) {
      playlist.next();
      if (playlist.isAtEnd()) {
        playlist.previous();
      } else {
        playCurrentFile();
      }
    }
  }
  
  private void previous() {
    if (status.playing || status.paused) {
      playlist.previous();
      if (playlist.isAtStart()) {
        playlist.next();
      } else {
        playCurrentFile();
      }
    }
  }
  
  private void playCurrentFile() {
    playFile(playlist.getCurrentFile());
  }
  
  private void unregisterBroadcastReceiver() {
    if (broadcastIsRegistered) {
      unregisterReceiver(noisyAudioStreamReceiver);
      broadcastIsRegistered = false;
    }
  }
  
  private void registerBroadcastReceiver() {
    IntentFilter noiseFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
    registerReceiver(noisyAudioStreamReceiver, noiseFilter);
    broadcastIsRegistered = true;
  }
  
  private void startTimer() {
    secondsTimer = new Timer(true);
    secondsTimer.scheduleAtFixedRate(new BroadcastTask(), 0, 1000);
  }
  
  private void stopTimer() {
    secondsTimer.cancel();
    secondsTimer.purge();
  }
  
  private void onResume() {
    registerBroadcastReceiver();
    status.stopped = false;
    getMediaInformation();
    showNotification();
    broadcastStatus();
      startTimer();
  }
  
  private void onStop() {
    status.stopped = true;
    broadcastStatus();
    stopTimer();
  }
  
  private void onPause() {
    status.paused = true;
    broadcastStatus();
    stopTimer();
  }
  
  private void setPlayerDataSource(String filePath) {
    status.file = filePath.replace("file://", "");
    try {
      player.setDataSource(filePath);
    } catch (IllegalArgumentException e1) {
      e1.printStackTrace();
    } catch (SecurityException e1) {
      e1.printStackTrace();
    } catch (IllegalStateException e1) {
      e1.printStackTrace();
    } catch (IOException e1) {
      e1.printStackTrace();
    }
  }
  
  private void preparePlayer() {
    try {
      player.prepare();
    } catch (IllegalStateException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  
  private void setTime(Bundle bundle) {
    int time = bundle.getInt(TIME);
    player.seekTo(time);
  }
  
  private void modifyPlaylist(Bundle bundle) {
    String addition = bundle.getString(PLAYLIST_ADDITION);
    String deletion = bundle.getString(PLAYLIST_DELETION);
    
    if (addition != null) {
      playlist.children.add(new MediaFile(addition));
    } else {
      playlist.children.remove(new MediaFile(deletion));
    }
  }
  
  private void toggleRepeat() {
    status.repeatMode = (status.repeatMode + 1) % 3;
    updatePlaylistModifiers();
    broadcastStatus();
  }
  
  private void toggleShuffle() {
    status.shuffled = ! status.shuffled;
    updatePlaylistModifiers();
    broadcastStatus();
  }
  
  private void updatePlaylistModifiers() {
    if (playlist != null) {
      playlist.setRepeating(status.repeatMode == MediaPlayerStatus.REPEAT_ONE);
      playlist.setRepeatingAll(status.repeatMode == MediaPlayerStatus.REPEAT_ALL);
      playlist.setShuffled(status.shuffled);
    }
  }
  
  private void getMediaInformation() {
    String title = DatabaseUtils.normalize(status.file);
    Cursor cursor = DatabaseUtils.getDB(this).query(DatabaseUtils.getGiantJoin(), new String[] {
        C.TAB_TITLES + "." + C.COL_ID, C.COL_TITLE, C.COL_ARTIST,
        C.COL_ALBUM, C.COL_YEAR, C.COL_RATING }, C.COL_FILE + " = \""
        + title + "\"", null, null, null, null);
    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
      status.title = cursor.getString(1);
      status.artist = cursor.getString(2);
      status.album = cursor.getString(3);
      status.year = cursor.getString(4);
      status.rating = cursor.getInt(5);
      status.cover = getAlbumArtFor(cursor.getString(3));
      cursor.moveToNext();
    }
    cursor.close();
  }
  
  private byte[] getAlbumArtFor(String name) {
    return (new AlbumCoverRetriever()).getBitmap(name, DatabaseUtils.getDB(this));
  }

  @Override
  public void onAudioFocusChange(int focusChange) {
    switch (focusChange) {
        case AudioManager.AUDIOFOCUS_GAIN: 
          break;
        case AudioManager.AUDIOFOCUS_LOSS: 
          break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 
          // Lost focus for a short time, but we have to stop
            // playback. We don't release the media player because playback
            // is likely to resume
          break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
            // Lost focus for a short time, but it's ok to keep playing
            // at an attenuated level
            break;
    }
  }
  
  private void broadcastStatus() {
    Intent intent = new Intent(PlayerService.STATUS_INTENT);
    intent.putExtra(EXTRA_STATUS, getPlayerStatus());
    sendBroadcast(intent);  
  }
  
  private MediaPlayerStatus getPlayerStatus() {
    status.playing = player.isPlaying();
    status.playlist = playlist;
    if (status.playing || status.paused) {
      status.length = player.getDuration();
      status.position = player.getCurrentPosition();
    }
    return status;
  }
  
  private class NoisyAudioStreamReceiver extends BroadcastReceiver {
      @Override
      public void onReceive(Context context, Intent intent) {
        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
          pause();
          }
      }
   }
  
  private class BroadcastTask extends TimerTask {
    @Override
    public void run() {
      broadcastStatus();      
    }    
  }
}




Java Source Code List

com.parnswir.unmp.AbstractFragment.java
com.parnswir.unmp.DirectoryChooserDialog.java
com.parnswir.unmp.DrawerActivity.java
com.parnswir.unmp.DrawerState.java
com.parnswir.unmp.LibraryFragment.java
com.parnswir.unmp.ListFragment.java
com.parnswir.unmp.MainActivity.java
com.parnswir.unmp.PlayerFragment.java
com.parnswir.unmp.PlayerService.java
com.parnswir.unmp.PlaylistsFragment.java
com.parnswir.unmp.SplashActivity.java
com.parnswir.unmp.core.AlbumCoverRetriever.java
com.parnswir.unmp.core.C.java
com.parnswir.unmp.core.CoverList.java
com.parnswir.unmp.core.DatabaseUtils.java
com.parnswir.unmp.core.IceCreamSandwichNotificationBuilder.java
com.parnswir.unmp.core.IconicAdapter.java
com.parnswir.unmp.core.ImageLoader.java
com.parnswir.unmp.core.ImageRetriever.java
com.parnswir.unmp.core.JellybeanNotificationBuilder.java
com.parnswir.unmp.core.MemoryCache.java
com.parnswir.unmp.core.MusicDatabaseHelper.java
com.parnswir.unmp.core.NotificationBuilder.java
com.parnswir.unmp.core.ProgressObservable.java
com.parnswir.unmp.core.ProjectResources.java
com.parnswir.unmp.core.Utils.java
com.parnswir.unmp.media.DefaultFileHandler.java
com.parnswir.unmp.media.FileAdditionThread.java
com.parnswir.unmp.media.FileCrawlerThread.java
com.parnswir.unmp.media.FileHandler.java
com.parnswir.unmp.media.FileRemovalThread.java
com.parnswir.unmp.media.MP3Handler.java
com.parnswir.unmp.media.MediaInformation.java
com.parnswir.unmp.media.MediaPlayerStatus.java
com.parnswir.unmp.media.PlaylistHandler.java
com.parnswir.unmp.playlist.MediaFile.java
com.parnswir.unmp.playlist.PlaylistElement.java
com.parnswir.unmp.playlist.Playlist.java
com.parnswir.unmp.playlist.parser.PlaylistParser.java
com.parnswir.unmp.playlist.parser.WPLParser.java