Android Open Source - prettygoodmusicplayer Music Playback Service






From Project

Back to project page prettygoodmusicplayer.

License

The source code is released under:

GNU General Public License

If you think the Android project prettygoodmusicplayer 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

/**
   The Pretty Good Music Player/*from   w ww.  jav  a  2 s  .c  om*/
   Copyright (C) 2014  Tyler Smith
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.smithdtyler.prettygoodmusicplayer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
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.Messenger;
import android.os.RemoteException;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Builder;
import android.util.Log;

public class MusicPlaybackService extends Service {
  static final int MSG_REGISTER_CLIENT = 1;
  static final int MSG_UNREGISTER_CLIENT = 2;

  // Playback control
  static final int MSG_PLAYPAUSE = 3;
  static final int MSG_NEXT = 4;
  static final int MSG_PREVIOUS = 5;
  static final int MSG_SET_PLAYLIST = 6;
  static final int MSG_PAUSE = 7;
  static final int MSG_PAUSE_IN_ONE_SEC = 8;
  static final int MSG_CANCEL_PAUSE_IN_ONE_SEC = 9;
  static final int MSG_TOGGLE_SHUFFLE = 10;
  static final int MSG_SEEK_TO = 11;

  // State management
  static final int MSG_REQUEST_STATE = 17;
  static final int MSG_SERVICE_STATUS = 18;
  static final int MSG_STOP_SERVICE = 19;

  public enum PlaybackState {
    PLAYING, PAUSED, UNKNOWN
  }

  static final String PRETTY_SONG_NAME = "PRETTY_SONG_NAME";
  static final String PRETTY_ARTIST_NAME = "PRETTY_ARTIST_NAME";
  static final String PRETTY_ALBUM_NAME = "PRETTY_ALBUM_NAME";
  static final String ALBUM_NAME = "ALBUM_NAME";
  static final String PLAYBACK_STATE = "PLAYBACK_STATE";
  static final String TRACK_DURATION = "TRACK_DURATION";
  static final String TRACK_POSITION = "TRACK_POSITION";
  static final String IS_SHUFFLING = "IS_SHUFFLING";

  private static final ComponentName cn = new ComponentName(
      MusicBroadcastReceiver.class.getPackage().getName(),
      MusicBroadcastReceiver.class.getName());

  private FileInputStream fis;
  private File songFile;
  private String[] songAbsoluteFileNames;
  private int songAbsoluteFileNamesPosition;

  private Timer timer;

  private AudioManager am;
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;
  private MediaPlayer mp;
  private static final String TAG = "MusicPlaybackService";
  private static boolean isRunning = false;

  private static int uniqueid = new String("Music Playback Service")
      .hashCode();

  private OnAudioFocusChangeListener audioFocusListener = new PrettyGoodAudioFocusChangeListener();

  private static IntentFilter filter = new IntentFilter();
  static {
    filter.addAction("android.intent.action.HEADSET_PLUG");
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
  }
  private static MusicBroadcastReceiver receiver = new MusicBroadcastReceiver();

  /**
   * Keeps track of all current registered clients.
   */
  List<Messenger> mClients = new ArrayList<Messenger>();

  final Messenger mMessenger = new Messenger(new IncomingHandler(this));

  public AudioManager mAudioManager;

  // These are used to report song progress when the song isn't started yet.
  private int lastDuration = 0;
  private int lastPosition = 0;
  public long audioFocusLossTime = 0;
  private long pauseTime = Long.MAX_VALUE;
  private boolean _shuffle = false;
  private List<Integer> shuffleFrontList = new ArrayList<Integer>();
  private Random random;
  private List<Integer> shuffleBackList = new ArrayList<Integer>();
  private String artist;
  private String artistAbsPath;
  private String album;
  private long lastResumeUpdateTime;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
      super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
      Log.i(TAG, "ServiceHandler got a message!" + msg);
    }
  }

  @Override
  public synchronized void onCreate() {
    Log.i(TAG, "Music Playback Service Created!");
    isRunning = true;
    random = new Random();

    mp = new MediaPlayer();

    mp.setOnCompletionListener(new OnCompletionListener() {

      @Override
      public void onCompletion(MediaPlayer mp) {
        Log.i(TAG, "Song complete");
        next();
      }

    });

    // https://developer.android.com/training/managing-audio/audio-focus.html
    audioFocusListener = new PrettyGoodAudioFocusChangeListener();

    // Get permission to play audio
    am = (AudioManager) getBaseContext().getSystemService(
        Context.AUDIO_SERVICE);

    HandlerThread thread = new HandlerThread("ServiceStartArguments");
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);

    // https://stackoverflow.com/questions/19474116/the-constructor-notification-is-deprecated
    // https://stackoverflow.com/questions/6406730/updating-an-ongoing-notification-quietly/15538209#15538209
    Intent resultIntent = new Intent(this, NowPlaying.class);
    resultIntent.putExtra("From_Notification", true);
    resultIntent.putExtra(AlbumList.ALBUM_NAME, album);
    resultIntent.putExtra(ArtistList.ARTIST_NAME, artist);
    resultIntent.putExtra(ArtistList.ARTIST_ABS_PATH_NAME, artistAbsPath);
    
    // Use the FLAG_ACTIVITY_CLEAR_TOP to prevent launching a second
    // NowPlaying if one already exists.
    resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
        resultIntent, 0);

    Builder builder = new NotificationCompat.Builder(
        this.getApplicationContext());

    String contentText = getResources().getString(R.string.ticker_text);
    if (songFile != null) {
      contentText = Utils.getPrettySongName(songFile);
    }

    Notification notification = builder
        .setContentText(contentText)
        .setSmallIcon(R.drawable.ic_pgmp_launcher)
        .setWhen(System.currentTimeMillis())
        .setContentIntent(pendingIntent)
        .setContentTitle(
            getResources().getString(R.string.notification_title))
        .build();

    startForeground(uniqueid, notification);

    timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
      public void run() {
        onTimerTick();
      }
    }, 0, 500L);

    Log.i(TAG, "Registering event receiver");
    mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    // Apparently audio registration is persistent across lots of things...
    // restarts, installs, etc.
    mAudioManager.registerMediaButtonEventReceiver(cn);
    // I tried to register this in the manifest, but it doesn't seen to
    // accept it, so I'll do it this way.
    getApplicationContext().registerReceiver(receiver, filter);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i("MyService", "Received start id " + startId + ": " + intent);
    if (intent == null) {
      // intent can be null if this is called by the OS due to
      // "START STICKY"
      // Start, but don't do anything until we get a message from the
      // user.
      return START_STICKY;
    }
    int command = intent.getIntExtra("Message", -1);
    if (command != -1) {
      Log.i(TAG, "I got a message! " + command);
      if (command == MSG_PLAYPAUSE) {
        Log.i(TAG, "I got a playpause message");
        playPause();
      } else if (command == MSG_PAUSE) {
        Log.i(TAG, "I got a pause message");
        pause();
      } else if (command == MSG_NEXT) {
        Log.i(TAG, "I got a next message");
        next();
      } else if (command == MSG_PREVIOUS) {
        Log.i(TAG, "I got a previous message");
        previous();
      } else if (command == MSG_STOP_SERVICE) {
        Log.i(TAG, "I got a stop message");
        timer.cancel();
        stopForeground(true);
        stopSelf();
      } else if (command == MSG_PAUSE_IN_ONE_SEC) {
        pauseTime = System.currentTimeMillis() + 1000;
      } else if (command == MSG_CANCEL_PAUSE_IN_ONE_SEC) {
        pauseTime = Long.MAX_VALUE;
      }
      return START_STICKY;
    }

    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    mServiceHandler.sendMessage(msg);
    // If we get killed, after returning from here, restart
    return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
    return mMessenger.getBinder();
  }

  // Receives messages from activities which want to control the jams
  private static class IncomingHandler extends Handler {
    MusicPlaybackService _service;

    private IncomingHandler(MusicPlaybackService service) {
      _service = service;
    }

    @Override
    public void handleMessage(Message msg) {
      Log.i(TAG, "Music Playback service got a message!");
      switch (msg.what) {
      case MSG_REGISTER_CLIENT:
        Log.i(TAG, "Got MSG_REGISTER_CLIENT");
        synchronized (_service.mClients) {
          _service.mClients.add(msg.replyTo);
        }
        break;
      case MSG_UNREGISTER_CLIENT:
        Log.i(TAG, "Got MSG_UNREGISTER_CLIENT");
        synchronized (_service.mClients) {
          _service.mClients.remove(msg.replyTo);
        }
        break;
      case MSG_PLAYPAUSE:
        // if we got a playpause message, assume that the user can hear
        // what's happening and wants to switch it.
        Log.i(TAG, "Got a playpause message!");
        // Assume that we're not changing songs
        _service.playPause();
        break;
      case MSG_NEXT:
        Log.i(TAG, "Got a next message!");
        _service.next();
        break;
      case MSG_PREVIOUS:
        Log.i(TAG, "Got a previous message!");
        _service.previous();
        break;
      case MSG_TOGGLE_SHUFFLE:
        Log.i(TAG, "Got a toggle shuffle message!");
        _service.toggleShuffle();
        break;
      case MSG_SET_PLAYLIST:
        Log.i(TAG, "Got a set playlist message!");
        _service.songAbsoluteFileNames = msg.getData().getStringArray(
            SongList.SONG_ABS_FILE_NAME_LIST);
        _service.songAbsoluteFileNamesPosition = msg.getData().getInt(
            SongList.SONG_ABS_FILE_NAME_LIST_POSITION);
        _service.songFile = new File(
            _service.songAbsoluteFileNames[_service.songAbsoluteFileNamesPosition]);
        _service.artist = msg.getData().getString(ArtistList.ARTIST_NAME);
        _service.artistAbsPath = msg.getData().getString(ArtistList.ARTIST_ABS_PATH_NAME);
        _service.album = msg.getData().getString(AlbumList.ALBUM_NAME);
        int songPosition = msg.getData().getInt(TRACK_POSITION, 0);
        _service.startPlayingFile(songPosition);
        _service.updateNotification();
        _service.resetShuffle();
        break;
      case MSG_REQUEST_STATE:
        Log.i(TAG, "Got a state request message!");
        break;
      case MSG_SEEK_TO:
        Log.i(TAG, "Got a seek request message!");
        int progress = msg.getData().getInt(TRACK_POSITION);
        _service.jumpTo(progress);
        break;
      default:
        super.handleMessage(msg);
      }
    }
  }

  private void onTimerTick() {
    long currentTime = System.currentTimeMillis();
    if (pauseTime < currentTime) {
      pause();
    }
    updateResumePosition();
    sendUpdateToClients();
  }
  
  private void updateResumePosition(){
    long currentTime = System.currentTimeMillis();
    if(currentTime - 10000 > lastResumeUpdateTime){
      if(mp != null && songFile != null && mp.isPlaying()){
        int pos = mp.getCurrentPosition();
        SharedPreferences prefs = getSharedPreferences("PrettyGoodMusicPlayer", MODE_PRIVATE);
        Log.i(TAG,
            "Preferences update success: "
                + prefs.edit()
                    .putString(songFile.getParentFile().getAbsolutePath(),songFile.getName() + "~" + pos)
                    .commit());
      }
      lastResumeUpdateTime = currentTime;
    }
  }


  private void sendUpdateToClients() {
    List<Messenger> toRemove = new ArrayList<Messenger>();
    synchronized (mClients) {
      for (Messenger client : mClients) {
        Message msg = Message.obtain(null, MSG_SERVICE_STATUS);
        Bundle b = new Bundle();
        if (songFile != null) {
          b.putString(PRETTY_SONG_NAME,
              Utils.getPrettySongName(songFile));
          b.putString(PRETTY_ALBUM_NAME, songFile.getParentFile()
              .getName());
          b.putString(PRETTY_ARTIST_NAME, songFile.getParentFile()
              .getParentFile().getName());
        } else {
          // songFile can be null while we're shutting down.
          b.putString(PRETTY_SONG_NAME, " ");
          b.putString(PRETTY_ALBUM_NAME, " ");
          b.putString(PRETTY_ARTIST_NAME, " ");
        }
        
        b.putBoolean(IS_SHUFFLING, this._shuffle);

        if (mp.isPlaying()) {
          b.putInt(PLAYBACK_STATE, PlaybackState.PLAYING.ordinal());
        } else {
          b.putInt(PLAYBACK_STATE, PlaybackState.PAUSED.ordinal());
        }
        // We might not be able to send the position right away if mp is
        // still being created
        // so instead let's send the last position we knew about.
        if (mp.isPlaying()) {
          lastDuration = mp.getDuration();
          lastPosition = mp.getCurrentPosition();
        }
        b.putInt(TRACK_DURATION, lastDuration);
        b.putInt(TRACK_POSITION, lastPosition);
        msg.setData(b);
        try {
          client.send(msg);
        } catch (RemoteException e) {
          e.printStackTrace();
          toRemove.add(client);
        }
      }

      for (Messenger remove : toRemove) {
        mClients.remove(remove);
      }
    }
  }

  public static boolean isRunning() {
    return isRunning;
  }

  @Override
  public synchronized void onDestroy() {
    super.onDestroy();
    am.abandonAudioFocus(MusicPlaybackService.this.audioFocusListener);
    mAudioManager.unregisterMediaButtonEventReceiver(cn);
    getApplicationContext().unregisterReceiver(receiver);
    mp.stop();
    mp.reset();
    mp.release();
    Log.i("MyService", "Service Stopped.");
    isRunning = false;
  }

  private synchronized void previous() {
    // if we're playing, and we're more than 3 seconds into the file, then
    // just
    // start the song over
    if (mp.isPlaying()) {
      int progressMillis = mp.getCurrentPosition();
      if (progressMillis > 3000) {
        mp.seekTo(0);
        return;
      }
    }

    mp.stop();
    mp.reset();
    try {
      fis.close();
    } catch (IOException e) {
      Log.w(TAG, "Failed to close the file");
      e.printStackTrace();
    }
    songAbsoluteFileNamesPosition = songAbsoluteFileNamesPosition - 1;
    if (songAbsoluteFileNamesPosition < 0) {
      songAbsoluteFileNamesPosition = songAbsoluteFileNames.length - 1;
    }
    String next = songAbsoluteFileNames[songAbsoluteFileNamesPosition];
    try {
      songFile = new File(next);
      fis = new FileInputStream(songFile);
      mp.setDataSource(fis.getFD());
      mp.prepare();
      mp.start();
    } catch (IOException e) {
      Log.w(TAG, "Failed to open " + next);
      e.printStackTrace();
      // Just go to the next song back
      previous();
    }
    updateNotification();
  }

  private synchronized void startPlayingFile(int songProgress) {
    // Have we loaded a file yet?
    if (mp.getDuration() > 0) {
      pause();
      mp.stop();
      mp.reset();
    }

    // open the file, pass it into the mp
    try {
      fis = new FileInputStream(songFile);
      mp.setDataSource(fis.getFD());
      mp.prepare();
      if(songProgress > 0){
        mp.seekTo(songProgress);
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IllegalArgumentException e) {
      e.printStackTrace();
    } catch (IllegalStateException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  
  private synchronized void jumpTo(int position){
    if(mp.isPlaying()){
      mp.seekTo(position);
    } else {
      // if we're paused but initialized, try to seek
      try{
        mp.seekTo(position);
        lastPosition = mp.getCurrentPosition();
      } catch (Exception e){
        Log.w(TAG, "Unable to seek to position, file may not have been loaded");
      }
    }
  }

  private synchronized void playPause() {
    if (mp.isPlaying()) {
      pause();
    } else {
      pauseTime = Long.MAX_VALUE;
      play();
    }
  }
  

  private synchronized void play() {
    if (mp.isPlaying()) {
      // do nothing
    } else {
      // Request audio focus for playback
      int result = am.requestAudioFocus(
          MusicPlaybackService.this.audioFocusListener,
          // Use the music stream.
          AudioManager.STREAM_MUSIC,
          // Request permanent focus.
          AudioManager.AUDIOFOCUS_GAIN);
      Log.d(TAG, "requestAudioFocus result = " + result);
      Log.i(TAG, "About to play " + songFile);

      if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        Log.d(TAG, "We got audio focus!");
        mp.start();
        updateNotification();
      } else {
        Log.e(TAG, "Unable to get audio focus");
      }
    }
  }

  private synchronized void pause() {
    if (mp.isPlaying()) {
      mp.pause();
    } else {
      // do nothing
    }
    updateNotification();
  }

  private void resetShuffle(){
    synchronized(shuffleFrontList){
      shuffleFrontList.clear();
      shuffleBackList.clear();
      for(int i = 0;i < songAbsoluteFileNames.length;i++){
        shuffleFrontList.add(i);
      }
    }
  }

  // Props to this fellow: https://stackoverflow.com/questions/5467174/how-to-implement-a-repeating-shuffle-thats-random-but-not-too-random
  private int grabNextShuffledPosition(){
    synchronized(shuffleFrontList){
      int threshold = (int) Math.ceil((songAbsoluteFileNames.length + 1) / 2);
      Log.d(TAG, "threshold: " + threshold);
      if(shuffleFrontList.size() < threshold){
        Log.d(TAG, "Shuffle queue is half empty, adding a new song...");
        shuffleFrontList.add(shuffleBackList.get(0));
        shuffleBackList.remove(0);
      }
      int rand = Math.abs(random.nextInt()) % shuffleFrontList.size();
      int loc = shuffleFrontList.get(rand);
      shuffleFrontList.remove(rand);
      shuffleBackList.add(loc);
      Log.i(TAG, "next position is: " + loc);
      String front = "";
      String back = "";
      for(int i : shuffleFrontList){
        front = front + "," + i;
      }
      for(int i : shuffleBackList){
        back = back + "," + i;
      }
      Log.i(TAG, "Front list = " + front);
      Log.i(TAG, "Back list = " + back);
      return loc;
    }
  }

  private synchronized void next() {
    mp.stop();
    mp.reset();
    try {
      fis.close();
    } catch (Exception e) {
      Log.w(TAG, "Failed to close the file");
      e.printStackTrace();
    }
    
    if(!this._shuffle){
      songAbsoluteFileNamesPosition = (songAbsoluteFileNamesPosition + 1)
          % songAbsoluteFileNames.length;
    } else {
      songAbsoluteFileNamesPosition = grabNextShuffledPosition();
    }
    String next = songAbsoluteFileNames[songAbsoluteFileNamesPosition];
    try {
      songFile = new File(next);
      fis = new FileInputStream(songFile);
      mp.setDataSource(fis.getFD());
      mp.prepare();
      mp.start();
    } catch (IOException e) {
      Log.w(TAG, "Failed to open " + next);
      e.printStackTrace();
      // I think our best chance is to go to the next song
      next();
    }
    updateNotification();
  }
  
  public void toggleShuffle() {
    this._shuffle = !this._shuffle ;
  }

  private void updateNotification() {
    // https://stackoverflow.com/questions/5528288/how-do-i-update-the-notification-text-for-a-foreground-service-in-android
    Intent resultIntent = new Intent(this, NowPlaying.class);
    // Use the FLAG_ACTIVITY_CLEAR_TOP to prevent launching a second
    // NowPlaying if one already exists.
    resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    resultIntent.putExtra("From_Notification", true);
    resultIntent.putExtra(AlbumList.ALBUM_NAME, album);
    resultIntent.putExtra(ArtistList.ARTIST_NAME, artist);
    resultIntent.putExtra(ArtistList.ARTIST_ABS_PATH_NAME, artistAbsPath);
    
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
        resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    Builder builder = new NotificationCompat.Builder(
        this.getApplicationContext());
    int icon = R.drawable.ic_pgmp_launcher;
    String contentText = getResources().getString(R.string.ticker_text);
    if (songFile != null) {
      SharedPreferences prefs = getSharedPreferences(
          "PrettyGoodMusicPlayer", MODE_PRIVATE);
      prefs.edit();
      File bestGuessMusicDir = Utils.getBestGuessMusicDirectory();
      String musicRoot = prefs.getString("ARTIST_DIRECTORY",
          bestGuessMusicDir.getAbsolutePath());
      contentText = Utils.getArtistName(songFile, musicRoot) + ": "
          + Utils.getPrettySongName(songFile);
      if (mp != null) {
        if (mp.isPlaying()) {
          icon = R.drawable.ic_pgmp_launcher;
        }
      }
    }
    
    Intent previousIntent = new Intent("Previous", null, this, MusicPlaybackService.class);
    previousIntent.putExtra("Message", MSG_PREVIOUS);
    PendingIntent previousPendingIntent = PendingIntent.getService(this, 0, previousIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    Intent nextIntent = new Intent("Next", null, this, MusicPlaybackService.class);
    nextIntent.putExtra("Message", MSG_NEXT);
    PendingIntent nextPendingIntent = PendingIntent.getService(this, 0, nextIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    
    PendingIntent playPausePendingIntent;
    Intent playPauseIntent = new Intent("PlayPause", null, this, MusicPlaybackService.class);
    playPauseIntent.putExtra("Message", MSG_PLAYPAUSE);
    playPausePendingIntent = PendingIntent.getService(this, 0, playPauseIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    int playPauseIcon;
    if(mp != null && mp.isPlaying()){
      playPauseIcon = R.drawable.ic_action_pause;
    } else {
      playPauseIcon = R.drawable.ic_action_play;
    }
    
    Notification notification = builder
        .setContentText(contentText)
        .setSmallIcon(icon)
        .setWhen(System.currentTimeMillis())
        .setContentIntent(pendingIntent)
        .setContentTitle(
            getResources().getString(R.string.notification_title))
        .addAction(R.drawable.ic_action_previous, "", previousPendingIntent)
        .addAction(playPauseIcon, "", playPausePendingIntent)
        .addAction(R.drawable.ic_action_next, "", nextPendingIntent)
        .build();

    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(uniqueid, notification);
  }

  private class PrettyGoodAudioFocusChangeListener implements
      AudioManager.OnAudioFocusChangeListener {

    private PlaybackState stateOnFocusLoss = PlaybackState.UNKNOWN;

    public void onAudioFocusChange(int focusChange) {
      Log.w(TAG, "Focus change received " + focusChange);
      if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
        Log.i(TAG, "AUDIOFOCUS_LOSS_TRANSIENT");
        if (mp.isPlaying()) {
          stateOnFocusLoss = PlaybackState.PLAYING;
        } else {
          stateOnFocusLoss = PlaybackState.PAUSED;
        }
        pause();
        MusicPlaybackService.this.audioFocusLossTime = System
            .currentTimeMillis();
        // Pause playback
      } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
        Log.i(TAG, "AUDIOFOCUS_GAIN");
        // If it's been less than 20 seconds, resume playback
        long curr = System.currentTimeMillis();
        if (((curr - MusicPlaybackService.this.audioFocusLossTime) < 30000)
            && stateOnFocusLoss == PlaybackState.PLAYING) {
          play();
        } else {
          Log.i(TAG,
              "It's been more than 30 seconds or we were paused, don't auto-play");
        }
      } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
        Log.i(TAG, "AUDIOFOCUS_LOSS");
        if (mp.isPlaying()) {
          stateOnFocusLoss = PlaybackState.PLAYING;
        } else {
          stateOnFocusLoss = PlaybackState.PAUSED;
        }
        pause();
        MusicPlaybackService.this.audioFocusLossTime = System
            .currentTimeMillis();
        // Stop playback
      } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
        Log.i(TAG, "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
        MusicPlaybackService.this.audioFocusLossTime = System
            .currentTimeMillis();
        if (mp.isPlaying()) {
          stateOnFocusLoss = PlaybackState.PLAYING;
        } else {
          stateOnFocusLoss = PlaybackState.PAUSED;
        }
        pause();
      } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) {
        Log.i(TAG, "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK");
        long curr = System.currentTimeMillis();
        if (((curr - MusicPlaybackService.this.audioFocusLossTime) < 30000)
            && stateOnFocusLoss == PlaybackState.PLAYING) {
          play();
        } else {
          Log.i(TAG,
              "It's been more than 30 seconds or we were paused, don't auto-play");
        }
      }
    }
  }

}




Java Source Code List

com.smithdtyler.prettygoodmusicplayer.AlbumList.java
com.smithdtyler.prettygoodmusicplayer.ArtistList.java
com.smithdtyler.prettygoodmusicplayer.MusicBroadcastReceiver.java
com.smithdtyler.prettygoodmusicplayer.MusicPlaybackService.java
com.smithdtyler.prettygoodmusicplayer.NowPlaying.java
com.smithdtyler.prettygoodmusicplayer.SettingsActivity.java
com.smithdtyler.prettygoodmusicplayer.SongList.java
com.smithdtyler.prettygoodmusicplayer.Utils.java