This example is using Android Annotation.
This is the activity of a player in a Podcast application
package br.com.podcast.podcast.view;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.graphics.Color;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Transformation;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.Extra;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.ViewById;
import br.com.podcast.podcast.R;
import br.com.podcast.podcast.domain.Episodio;
import br.com.podcast.podcast.domain.Podcast;
import br.com.podcast.podcast.service.background.player.PlayerBinder;
import br.com.podcast.podcast.service.background.player.PlayerCallBack;
import br.com.podcast.podcast.service.background.player.PlayerService;
import br.com.podcast.podcast.service.background.player.PlayerService_;
import br.com.podcast.podcast.util.DateUtils;
import br.com.podcast.podcast.util.InternetUtil;
import br.com.podcast.podcast.util.Load;
import jp.wasabeef.picasso.transformations.BlurTransformation;
import jp.wasabeef.picasso.transformations.ColorFilterTransformation;
import static android.os.Build.VERSION;
import static android.os.Build.VERSION_CODES;
@EActivity(R.layout.activity_player)
public class PlayerActivity extends AppCompatActivity implements ServiceConnection, PlayerCallBack {
private PlayerService playerService;
private boolean connected = false;
private Load load;
@ViewById
ImageView background;
@ViewById
TextView title;
@ViewById
ImageView logo;
@ViewById
TextView progressTime;
@ViewById
TextView duration;
@ViewById
SeekBar progressBar;
@ViewById
ImageView playPause;
@ViewById
TextView titleEpisodio;
@ViewById
Toolbar toolbar;
@Extra
Podcast podcast;
@Extra
Integer selectedPodcast;
@Extra
Boolean autoPlay;
@AfterViews
void afterViewPlayerActivity(){
PlayerService_.intent(getApplication()).start();
doBindService();
load = new Load(this, Load.Color.DARK);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
load.show();
}
private void init(){
playPause.setSelected(true);
resetSeekBar();
title.setText(podcast.getNome());
//Imagem do album
int size = (InternetUtil.screenWidth(this) / 5) * 4;
Picasso.with(this).load(podcast.getImage()).resize(size,size).placeholder(R.drawable.holder_quad).into(logo);
//Imagem de fundo
Transformation blur = new BlurTransformation(this, 12, 4);
Transformation filterColor = new ColorFilterTransformation(Color.argb(130, 0, 0, 0));
Picasso.with(this).load(podcast.getImage()).transform(blur).transform(filterColor).into(background);
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.BLACK);
}
playerService.setPodcast(podcast, selectedPodcast, autoPlay);
}
private void resetSeekBar(){
progressBar.setProgress(0);
progressBar.setSecondaryProgress(0);
progressTime.setText("00:00");
duration.setText("00:00");
}
//Clicks Controll
@Click
void back(){
if(connected){
playerService.playPreview();
}
}
@Click
void back30(){
if(connected) {
int newPosition = playerService.getPosition() - (30 * 1000);
if(newPosition < 0 ){
playerService.seekTo(0);
onProgress(0);
}else{
playerService.seekTo(newPosition); //30 segundos
onProgress(newPosition);
}
}
}
@Click
void playPause(){
if(connected) {
if (playerService.isPlaying()) {
playerService.pause();
} else {
playerService.play();
}
playPause.setSelected(!playerService.isPlaying());
}
}
@Click
void nex30(){
if(connected){
int newPosition = playerService.getPosition() + (30 * 1000);
if(newPosition > playerService.getDuration()){
playerService.playNext();
onProgress(playerService.getDuration());
}else{
playerService.seekTo(newPosition); //30 segundos
onProgress(newPosition);
}
}
}
@Click
void next(){
if(connected){
playerService.playNext();
}
}
//Listeners player
@Override
public void onProgress(int progress) {
progressBar.setProgress(progress);
progressTime.setText(DateUtils.toClockTimestampInSecondsFormat(playerService.getPosition()));
}
@Override
public void onPrepare(Episodio episodio) {
load.hide();
progressBar.setMax(playerService.getDuration());
duration.setText(DateUtils.toClockTimestampInSecondsFormat(playerService.getDuration()));
progressBar.setProgress(playerService.getPosition());
progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (connected) {
progressTime.setText(DateUtils.toClockTimestampInSecondsFormat(progress));
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
playerService.stopProgressUpdate();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (connected) {
playerService.seekTo(seekBar.getProgress());
playerService.startProgressUpdate();
}
}
});
progressTime.setText(DateUtils.toClockTimestampInSecondsFormat(playerService.getPosition()));
playPause.setSelected(!playerService.isPlaying());
titleEpisodio.setText(episodio.getTitulo());
}
@Override
public void onPlayer() {
playPause.setSelected(!playerService.isPlaying());
}
@Override
public void onPause_() {
playPause.setSelected(!playerService.isPlaying());
}
@Override
public void onEpisodioChange(Episodio episodio) {
titleEpisodio.setText(episodio.getTitulo());
}
@Override
public void onError(String message) {
load.hide();
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
@Override
public void onBufferInit() {
load.show();
}
@Override
public void onBufferFinish() {
load.hide();
}
@Override
public void onBufferUpdate(int percent) {
progressBar.setSecondaryProgress((int)(playerService.getDuration() * (percent / 100.0)));
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
playerService = ((PlayerBinder) binder).getService();
playerService.setPlayerCallBack(this);
init();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
playerService = null;
connected = false;
}
private void doBindService(){
try{
if(!connected){
bindService(PlayerService_.intent(getApplication()).get(), this, 0);
connected = true;
}
}catch (Exception e){
e.printStackTrace();
}
}
private void doUnbindService(){
try{
if(connected){
unbindService(this);
connected = false;
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
doUnbindService();
super.onDestroy();
}
@OptionsItem(android.R.id.home)
void homeSelected() {
finish();
}
}
}
This Class is a Service that will be our PlayerService. The service ensures that the audio will continue to run even if the application is placed in the background.
package br.com.podcast.podcast.service.background.player;
import android.app.Service;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import org.androidannotations.annotations.EService;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import br.com.podcast.podcast.domain.Podcast;
import br.com.podcast.podcast.domain.helper.FinishGeneralEventBusHelper;
import br.com.podcast.podcast.domain.helper.PlayerCommandEventBusHelper;
import br.com.podcast.podcast.domain.helper.PlayerStatusEventBusHelper;
import lombok.Setter;
@EService
public class PlayerService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener,
CallbackEventsCallAndPhone, MediaPlayer.OnInfoListener, MediaPlayer.OnBufferingUpdateListener, RemoteControlListener {
private final IBinder playerBinder = new PlayerBinder(this);
private MediaPlayer player;
private int currentPosition = 0;
private final Handler handler = new Handler();
private boolean isMyPause = false;
private final Runnable callBackRunnable = new Runnable() {
public void run() {
if(player.isPlaying() && playerCallBack != null)
playerCallBack.onProgress(player.getCurrentPosition());
}
};
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> callBackHandle;
private RemoteControlNotification remoteControlNotification;
private Podcast podcast;
@Setter
private PlayerCallBack playerCallBack;
public void onCreate(){
super.onCreate();
initPlayer();
PlayerIntentReceiver.getInstance(this, getApplicationContext()).register();
EventBus.getDefault().register(this);
remoteControlNotification = RemoteControlNotification.getInstance(this, this);
remoteControlNotification.register();
}
private void initPlayer() {
player = new MediaPlayer();
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
player.setOnInfoListener(this);
player.setOnBufferingUpdateListener(this);
}
@Override
public IBinder onBind(Intent intent) {
return playerBinder;
}
@Override
public boolean onUnbind(Intent intent){
playerCallBack = null;
stopProgressUpdate();
return false;
}
public void startProgressUpdate() {
if(player.isPlaying() && playerCallBack != null){
if (!scheduler.isShutdown())
callBackHandle = scheduler.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
handler.post(callBackRunnable);
}
}, 500, 500, TimeUnit.MILLISECONDS);
}
}
public void stopProgressUpdate(){
if(callBackHandle != null)
callBackHandle.cancel(false);
}
public void stopService(){
stopSelf();
}
public void setPodcast(Podcast podcast, Integer selectedPosition, Boolean autoPlay){
if(this.podcast != null) {
if(podcast.getUrl().equals(this.podcast.getUrl())){
if(isPlaying()){
if(selectedPosition != null && selectedPosition >= 0 ){
pause();
jumpTo(selectedPosition);
}
playerCallBack.onPrepare(this.podcast.getEpisodios().get(currentPosition));
}else{
if(selectedPosition != null && selectedPosition >= 0 )
currentPosition = selectedPosition;
if(autoPlay != null && autoPlay)
play();
playerCallBack.onPrepare(this.podcast.getEpisodios().get(currentPosition));
}
}else{
this.podcast = podcast;
if(isPlaying()) {
pause();
}
currentPosition = 0;
resetPlayer();
}
}else{
this.podcast = podcast;
if(selectedPosition != null && selectedPosition >= 0 )
currentPosition = selectedPosition;
resetPlayer();
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onCommand(final PlayerCommandEventBusHelper helper){
switch (helper.command){
case NEXT:
playNext();
break;
case PAUSE:
pause();
break;
case PlAYER:
play();
break;
case PREVIEW:
playPreview();
break;
case STOP:
stopPodcast();
break;
case STATUS_REQUEST:
break;
}
EventBus.getDefault().post(getStatus());
}
private PlayerStatusEventBusHelper getStatus(){
PlayerStatusEventBusHelper helper = new PlayerStatusEventBusHelper();
helper.podcast = podcast;
helper.episodioCorrente = currentPosition;
if(isPlaying()) {
helper.status = PlayerStatusEventBusHelper.Status.PLAYING;
}else {
if (podcast != null)
helper.status = PlayerStatusEventBusHelper.Status.PAUSED;
else
helper.status = PlayerStatusEventBusHelper.Status.STOPED;
}
return helper;
}
public void stopPodcast(){
stop();
podcast = null;
currentPosition = 0;
initPlayer();
}
//Comandos da notificação
@Override
public void onPlay() {
play();
}
@Override
public void onPause() {
pause();
}
@Override
public void onNext30() {
int newPosition = getPosition() - (30 * 1000);
if(newPosition < 0 ){
seekTo(0);
if(playerCallBack != null)
playerCallBack.onProgress(0);
}else{
seekTo(newPosition); //30 segundos
if(playerCallBack != null)
playerCallBack.onProgress(newPosition);
}
}
@Override
public void onPreview30() {
int newPosition = getPosition() + (30 * 1000);
if(newPosition > getDuration()){
playNext();
if(playerCallBack != null)
playerCallBack.onProgress(getDuration());
}else{
seekTo(newPosition); //30 segundos
if(playerCallBack != null)
playerCallBack.onProgress(newPosition);
}
}
//Commandos do Player
public void resetPlayer(){
try{
if(player.isLooping())
player.stop();
player.release();
initPlayer();
if(playerCallBack != null)
playerCallBack.onEpisodioChange(podcast.getEpisodios().get(currentPosition));
player.setDataSource(podcast.getEpisodios().get(currentPosition).getUrl());
player.prepareAsync();
}catch(Exception e){
e.printStackTrace();
playerCallBack.onError("Erro ao chamar o servidor de podcast");
}
remoteControlNotification.playNotification(podcast, currentPosition);
}
public void playNext(){
stopProgressUpdate();
currentPosition++;
if(currentPosition >= podcast.getEpisodios().size())
currentPosition = 0;
resetPlayer();
}
public void play(){
if(!player.isPlaying())
player.start();
if(playerCallBack != null){
playerCallBack.onEpisodioChange(podcast.getEpisodios().get(currentPosition));
playerCallBack.onPlayer();
startProgressUpdate();
}
remoteControlNotification.playNotification(podcast, currentPosition);
}
public void pause(){
if(player.isPlaying())
player.pause();
if(playerCallBack != null)
playerCallBack.onPause_();
stopProgressUpdate();
remoteControlNotification.pauseNotification(podcast, currentPosition);
}
public void seekTo(int position){
player.seekTo(position);
}
public void jumpTo(int position){
pause();
currentPosition = position;
resetPlayer();
}
public void playPreview(){
stopProgressUpdate();
currentPosition--;
if(currentPosition < 0)
currentPosition = podcast.getEpisodios().size() - 1;
resetPlayer();
}
public void stop(){
player.stop();
player.release();
stopProgressUpdate();
remoteControlNotification.stopNotification();
}
public boolean isPlaying(){
try{
return player.isPlaying();
}catch (IllegalStateException e){
e.printStackTrace();
}
return false;
}
public int getDuration(){
return player.getDuration();
}
public int getPosition(){
return player.getCurrentPosition();
}
//CallBacks
@Override
public void onPhoneOut() {
pause();
}
@Override
public void onCalling() {
if(player.isPlaying()){
isMyPause = true;
pause();
}
}
@Override
public void onCallStart() {
if(player.isPlaying()){
isMyPause = true;
pause();
}
}
@Override
public void onCallFinish() {
if(isMyPause){
isMyPause = false;
play();
}
}
@Override
public void onBufferingUpdate(MediaPlayer mediaPlayer, int percent) {
if(playerCallBack != null)
playerCallBack.onBufferUpdate(percent);
}
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
stopProgressUpdate();
if(player.getCurrentPosition() > 0){
playNext();
}
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
switch (what){
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
playerCallBack.onError("Erro no servidor");
System.out.println("Erro no servidor");
return true;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
playerCallBack.onError("Servidor do Podcast encontra se fora do ar");
System.out.println("Servidor do Podcast encontra se fora do ar");
return true;
}
switch (extra){
case MediaPlayer.MEDIA_ERROR_IO:
playerCallBack.onError("Existe um problema na rede ou no Servidor do podcast");
System.out.println("Existe um problema na rede ou no Servidor do podcast");
return true;
case MediaPlayer.MEDIA_ERROR_MALFORMED:
playerCallBack.onError("Este podcast esta com audio corrompido");
System.out.println("Este podcast esta com audio corrompido");
return true;
case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
playerCallBack.onError("Erro no servidor");
System.out.println("Erro no servidor");
return true;
case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
playerCallBack.onError("Servidor de podcast temporariamente indisponível");
System.out.println("Servidor de podcast temporariamente indisponível");
return true;
}
return false;
}
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
switch (what) {
case MediaPlayer.MEDIA_INFO_BUFFERING_START:
if(playerCallBack != null)
playerCallBack.onBufferInit();
pause();
break;
case MediaPlayer.MEDIA_INFO_BUFFERING_END:
if(playerCallBack != null)
playerCallBack.onBufferFinish();
play();
break;
}
return false;
}
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
if(playerCallBack != null)
playerCallBack.onPrepare(this.podcast.getEpisodios().get(currentPosition));
play();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onFinishAplication(FinishGeneralEventBusHelper helper){
stop();
onDestroy();
}
@Override
public void onDestroy() {
PlayerIntentReceiver.getInstance(this, getApplicationContext()).unregister();
EventBus.getDefault().unregister(this);
remoteControlNotification.stopNotification();
remoteControlNotification.unregister();
stopForeground(true);
}
}