diff options
author | Christian Schneppe <christian@pix-art.de> | 2017-09-24 21:27:52 +0200 |
---|---|---|
committer | Christian Schneppe <christian@pix-art.de> | 2017-09-24 21:30:58 +0200 |
commit | 83f362c8b4f25d56ab2a74e37acd6b0fd0125a9c (patch) | |
tree | 01b2b07c70a307a526944133b6dfc88f3e2c0604 /src/main/java/de/pixart/messenger/services/AudioPlayer.java | |
parent | 259d29518331c4517c36e2baf073615fb7bf193f (diff) |
refactored AudioPlayer
Diffstat (limited to '')
-rw-r--r-- | src/main/java/de/pixart/messenger/services/AudioPlayer.java | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/main/java/de/pixart/messenger/services/AudioPlayer.java b/src/main/java/de/pixart/messenger/services/AudioPlayer.java new file mode 100644 index 000000000..6c3b55344 --- /dev/null +++ b/src/main/java/de/pixart/messenger/services/AudioPlayer.java @@ -0,0 +1,280 @@ +package de.pixart.messenger.services; + +import android.content.res.ColorStateList; +import android.media.MediaPlayer; +import android.os.Build; +import android.os.Handler; +import android.support.v4.content.ContextCompat; +import android.view.View; +import android.widget.ImageButton; +import android.widget.RelativeLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +import java.lang.ref.WeakReference; +import java.util.Locale; + +import de.pixart.messenger.R; +import de.pixart.messenger.entities.Message; +import de.pixart.messenger.ui.adapter.MessageAdapter; +import de.pixart.messenger.utils.WeakReferenceSet; + +public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompletionListener, SeekBar.OnSeekBarChangeListener, Runnable { + + private static final int REFRESH_INTERVAL = 250; + private static final Object LOCK = new Object(); + private static MediaPlayer player = null; + private static Message currentlyPlayingMessage = null; + private final MessageAdapter messageAdapter; + private final WeakReferenceSet<RelativeLayout> audioPlayerLayouts = new WeakReferenceSet<>(); + + private final Handler handler = new Handler(); + + public AudioPlayer(MessageAdapter adapter) { + this.messageAdapter = adapter; + synchronized (AudioPlayer.LOCK) { + if (AudioPlayer.player != null) { + AudioPlayer.player.setOnCompletionListener(this); + } + } + } + + private static String formatTime(int ms) { + return String.format(Locale.ENGLISH, "%d:%02d", ms / 60000, Math.min(Math.round((ms % 60000) / 1000f), 59)); + } + + public void init(RelativeLayout audioPlayer, Message message) { + synchronized (AudioPlayer.LOCK) { + audioPlayer.setTag(message); + if (init(ViewHolder.get(audioPlayer), message)) { + this.audioPlayerLayouts.addWeakReferenceTo(audioPlayer); + this.stopRefresher(true); + } else { + this.audioPlayerLayouts.removeWeakReferenceTo(audioPlayer); + } + } + } + + private boolean init(ViewHolder viewHolder, Message message) { + viewHolder.runtime.setTextColor(this.messageAdapter.getMessageTextColor(viewHolder.darkBackground, false)); + viewHolder.progress.setOnSeekBarChangeListener(this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ColorStateList color = ContextCompat.getColorStateList(messageAdapter.getContext(), viewHolder.darkBackground ? R.color.white70 : R.color.bubble); + viewHolder.progress.setThumbTintList(color); + viewHolder.progress.setProgressTintList(color); + } + viewHolder.playPause.setAlpha(viewHolder.darkBackground ? 0.7f : 0.57f); + viewHolder.playPause.setOnClickListener(this); + if (message == currentlyPlayingMessage) { + if (AudioPlayer.player != null && AudioPlayer.player.isPlaying()) { + viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp); + viewHolder.progress.setEnabled(true); + } else { + viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp); + viewHolder.progress.setEnabled(false); + } + return true; + } else { + viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp); + viewHolder.runtime.setText(formatTime(message.getFileParams().runtime)); + viewHolder.progress.setProgress(0); + viewHolder.progress.setEnabled(false); + return false; + } + } + + @Override + public synchronized void onClick(View v) { + if (v.getId() == R.id.play_pause) { + synchronized (LOCK) { + startStop((ImageButton) v); + } + } + } + + private void startStop(ImageButton playPause) { + final RelativeLayout audioPlayer = (RelativeLayout) playPause.getParent(); + final ViewHolder viewHolder = ViewHolder.get(audioPlayer); + final Message message = (Message) audioPlayer.getTag(); + if (startStop(viewHolder, message)) { + this.audioPlayerLayouts.clear(); + this.audioPlayerLayouts.addWeakReferenceTo(audioPlayer); + stopRefresher(true); + } + } + + private boolean playPauseCurrent(ViewHolder viewHolder) { + viewHolder.playPause.setAlpha(viewHolder.darkBackground ? 0.7f : 0.57f); + if (player.isPlaying()) { + viewHolder.progress.setEnabled(false); + player.pause(); + viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp); + } else { + viewHolder.progress.setEnabled(true); + player.start(); + this.stopRefresher(true); + viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp); + } + return false; + } + + private boolean play(ViewHolder viewHolder, Message message) { + AudioPlayer.player = new MediaPlayer(); + try { + AudioPlayer.currentlyPlayingMessage = message; + AudioPlayer.player.setDataSource(messageAdapter.getFileBackend().getFile(message).getAbsolutePath()); + AudioPlayer.player.setOnCompletionListener(this); + AudioPlayer.player.prepare(); + AudioPlayer.player.start(); + viewHolder.progress.setEnabled(true); + viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp); + return true; + } catch (Exception e) { + AudioPlayer.currentlyPlayingMessage = null; + return false; + } + } + + private boolean startStop(ViewHolder viewHolder, Message message) { + if (message == currentlyPlayingMessage && player != null) { + return playPauseCurrent(viewHolder); + } + if (AudioPlayer.player != null) { + stopCurrent(); + } + return play(viewHolder, message); + } + + private void stopCurrent() { + if (AudioPlayer.player.isPlaying()) { + AudioPlayer.player.stop(); + } + AudioPlayer.player.release(); + AudioPlayer.player = null; + resetPlayerUi(); + } + + private void resetPlayerUi() { + for (WeakReference<RelativeLayout> audioPlayer : audioPlayerLayouts) { + resetPlayerUi(audioPlayer.get()); + } + } + + private void resetPlayerUi(RelativeLayout audioPlayer) { + if (audioPlayer == null) { + return; + } + final ViewHolder viewHolder = ViewHolder.get(audioPlayer); + final Message message = (Message) audioPlayer.getTag(); + viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp); + if (message != null) { + viewHolder.runtime.setText(formatTime(message.getFileParams().runtime)); + } + viewHolder.progress.setProgress(0); + viewHolder.progress.setEnabled(false); + } + + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + synchronized (AudioPlayer.LOCK) { + this.stopRefresher(false); + if (AudioPlayer.player == mediaPlayer) { + AudioPlayer.currentlyPlayingMessage = null; + AudioPlayer.player = null; + } + mediaPlayer.release(); + resetPlayerUi(); + } + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + synchronized (AudioPlayer.LOCK) { + final RelativeLayout audioPlayer = (RelativeLayout) seekBar.getParent(); + final Message message = (Message) audioPlayer.getTag(); + if (fromUser && message == AudioPlayer.currentlyPlayingMessage) { + float percent = progress / 100f; + int duration = AudioPlayer.player.getDuration(); + int seekTo = Math.round(duration * percent); + AudioPlayer.player.seekTo(seekTo); + } + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } + + public void stop() { + synchronized (AudioPlayer.LOCK) { + stopRefresher(false); + if (AudioPlayer.player != null) { + stopCurrent(); + } + AudioPlayer.currentlyPlayingMessage = null; + } + } + + private void stopRefresher(boolean runOnceMore) { + this.handler.removeCallbacks(this); + if (runOnceMore) { + this.handler.post(this); + } + } + + @Override + public void run() { + synchronized (AudioPlayer.LOCK) { + if (AudioPlayer.player != null) { + boolean renew = false; + final int current = player.getCurrentPosition(); + final int duration = player.getDuration(); + for (WeakReference<RelativeLayout> audioPlayer : audioPlayerLayouts) { + renew |= refreshAudioPlayer(audioPlayer.get(), current, duration); + } + if (renew && AudioPlayer.player.isPlaying()) { + handler.postDelayed(this, REFRESH_INTERVAL); + } + } + } + } + + private boolean refreshAudioPlayer(RelativeLayout audioPlayer, int current, int duration) { + if (audioPlayer == null || audioPlayer.getVisibility() != View.VISIBLE) { + return false; + } + final ViewHolder viewHolder = ViewHolder.get(audioPlayer); + viewHolder.progress.setProgress(current * 100 / duration); + viewHolder.runtime.setText(formatTime(current) + " / " + formatTime(duration)); + return true; + } + + public static class ViewHolder { + private TextView runtime; + private SeekBar progress; + private ImageButton playPause; + private boolean darkBackground = false; + + public static ViewHolder get(RelativeLayout audioPlayer) { + ViewHolder viewHolder = (ViewHolder) audioPlayer.getTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER); + if (viewHolder == null) { + viewHolder = new ViewHolder(); + viewHolder.runtime = (TextView) audioPlayer.findViewById(R.id.runtime); + viewHolder.progress = (SeekBar) audioPlayer.findViewById(R.id.progress); + viewHolder.playPause = (ImageButton) audioPlayer.findViewById(R.id.play_pause); + audioPlayer.setTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER, viewHolder); + } + return viewHolder; + } + + public void setDarkBackground(boolean darkBackground) { + this.darkBackground = darkBackground; + } + } +}
\ No newline at end of file |