From ecad9ad9294e951f9350635ace661e5ab981a39b Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Thu, 30 Aug 2018 22:10:21 +0200 Subject: switch between earphone and speaker while playing sounds --- .../de/pixart/messenger/services/AudioPlayer.java | 106 ++++++++++++++++++++- .../messenger/ui/adapter/MessageAdapter.java | 10 +- 2 files changed, 110 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main/java/de/pixart/messenger/services/AudioPlayer.java b/src/main/java/de/pixart/messenger/services/AudioPlayer.java index e1f97ef1a..120a810e1 100644 --- a/src/main/java/de/pixart/messenger/services/AudioPlayer.java +++ b/src/main/java/de/pixart/messenger/services/AudioPlayer.java @@ -1,13 +1,20 @@ package de.pixart.messenger.services; import android.Manifest; +import android.content.Context; import android.content.pm.PackageManager; import android.content.res.ColorStateList; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Build; import android.os.Handler; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; +import android.util.Log; import android.view.View; import android.widget.ImageButton; import android.widget.RelativeLayout; @@ -17,6 +24,7 @@ import android.widget.TextView; import java.lang.ref.WeakReference; import java.util.Locale; +import de.pixart.messenger.Config; import de.pixart.messenger.R; import de.pixart.messenger.entities.Message; import de.pixart.messenger.ui.ConversationsActivity; @@ -24,14 +32,16 @@ import de.pixart.messenger.ui.adapter.MessageAdapter; import de.pixart.messenger.ui.util.PendingItem; import de.pixart.messenger.utils.WeakReferenceSet; -public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompletionListener, SeekBar.OnSeekBarChangeListener, Runnable { +public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompletionListener, SeekBar.OnSeekBarChangeListener, Runnable, SensorEventListener { private static final int REFRESH_INTERVAL = 250; private static final Object LOCK = new Object(); - public static MediaPlayer player = null; + private static MediaPlayerWrapper player = null; private static Message currentlyPlayingMessage = null; private final MessageAdapter messageAdapter; private final WeakReferenceSet audioPlayerLayouts = new WeakReferenceSet<>(); + private final SensorManager sensorManager; + private final Sensor proximitySensor; private final PendingItem> pendingOnClickView = new PendingItem<>(); @@ -39,6 +49,8 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti public AudioPlayer(MessageAdapter adapter) { this.messageAdapter = adapter; + this.sensorManager = (SensorManager) adapter.getActivity().getSystemService(Context.SENSOR_SERVICE); + this.proximitySensor = sensorManager != null ? sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) : null; synchronized (AudioPlayer.LOCK) { if (AudioPlayer.player != null) { AudioPlayer.player.setOnCompletionListener(this); @@ -91,6 +103,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti viewHolder.progress.setProgress(0); viewHolder.progress.setEnabled(false); messageAdapter.flagScreenOff(); + messageAdapter.flagEnableInputs(); return false; } } @@ -126,6 +139,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti viewHolder.progress.setEnabled(false); player.pause(); messageAdapter.flagScreenOff(); + messageAdapter.flagEnableInputs(); viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp); } else { viewHolder.progress.setEnabled(true); @@ -137,21 +151,36 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti return false; } - private boolean play(ViewHolder viewHolder, Message message) { - AudioPlayer.player = new MediaPlayer(); + private void play(ViewHolder viewHolder, Message message, boolean earpiece, double progress) { + if (play(viewHolder, message, earpiece)) { + AudioPlayer.player.seekTo((int) (AudioPlayer.player.getDuration() * progress)); + } + } + + private boolean play(ViewHolder viewHolder, Message message, boolean earpiece) { + AudioPlayer.player = new MediaPlayerWrapper(); try { AudioPlayer.currentlyPlayingMessage = message; + AudioPlayer.player.setAudioStreamType(earpiece ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC); AudioPlayer.player.setDataSource(messageAdapter.getFileBackend().getFile(message).getAbsolutePath()); AudioPlayer.player.setOnCompletionListener(this); AudioPlayer.player.prepare(); AudioPlayer.player.start(); messageAdapter.flagScreenOn(); + if (earpiece) { + messageAdapter.flagDisableInputs(); + } else { + messageAdapter.flagEnableInputs(); + } viewHolder.progress.setEnabled(true); viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp); + sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL); return true; } catch (Exception e) { messageAdapter.flagScreenOff(); + messageAdapter.flagEnableInputs(); AudioPlayer.currentlyPlayingMessage = null; + sensorManager.unregisterListener(this); return false; } } @@ -173,7 +202,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti if (AudioPlayer.player != null) { stopCurrent(); } - return play(viewHolder, message); + return play(viewHolder, message, false); } private void stopCurrent() { @@ -182,8 +211,10 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti } AudioPlayer.player.release(); messageAdapter.flagScreenOff(); + messageAdapter.flagEnableInputs(); AudioPlayer.player = null; resetPlayerUi(); + sensorManager.unregisterListener(this); } private void resetPlayerUi() { @@ -216,7 +247,9 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti } mediaPlayer.release(); messageAdapter.flagScreenOff(); + messageAdapter.flagEnableInputs(); resetPlayerUi(); + sensorManager.unregisterListener(this); } } @@ -288,6 +321,55 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti return true; } + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor.getType() != Sensor.TYPE_PROXIMITY) { + return; + } + if (AudioPlayer.player == null || !AudioPlayer.player.isPlaying()) { + return; + } + int streamType; + if (event.values[0] < 5f && event.values[0] != proximitySensor.getMaximumRange()) { + streamType = AudioManager.STREAM_VOICE_CALL; + } else { + streamType = AudioManager.STREAM_MUSIC; + } + double position = AudioPlayer.player.getCurrentPosition(); + double duration = AudioPlayer.player.getDuration(); + double progress = position / duration; + if (AudioPlayer.player.getAudioStreamType() != streamType) { + synchronized (AudioPlayer.LOCK) { + AudioPlayer.player.stop(); + AudioPlayer.player.release(); + AudioPlayer.player = null; + try { + ViewHolder currentViewHolder = getCurrentViewHolder(); + if (currentViewHolder != null) { + Log.d(Config.LOGTAG, "AudioPlayer start playing - progress: " + progress); + play(currentViewHolder, currentlyPlayingMessage, streamType == AudioManager.STREAM_VOICE_CALL, progress); + } + } catch (Exception e) { + Log.w(Config.LOGTAG, "AudioPlayer Exception: " + e); + } + } + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int i) { + } + + private ViewHolder getCurrentViewHolder() { + for (WeakReference audioPlayer : audioPlayerLayouts) { + final Message message = (Message) audioPlayer.get().getTag(); + if (message == currentlyPlayingMessage) { + return ViewHolder.get(audioPlayer.get()); + } + } + return null; + } + public static class ViewHolder { private TextView runtime; private SeekBar progress; @@ -310,4 +392,18 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti this.darkBackground = darkBackground; } } + + private static class MediaPlayerWrapper extends MediaPlayer { + private int streamType; + + private int getAudioStreamType() { + return streamType; + } + + @Override + public void setAudioStreamType(int streamType) { + this.streamType = streamType; + super.setAudioStreamType(streamType); + } + } } \ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java index 519b01c1a..f3b04ff8a 100644 --- a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java +++ b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java @@ -112,8 +112,8 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie public MessageAdapter(XmppActivity activity, List messages) { super(activity, 0, messages); - this.audioPlayer = new AudioPlayer(this); this.activity = activity; + this.audioPlayer = new AudioPlayer(this); metrics = getContext().getResources().getDisplayMetrics(); updatePreferences(); } @@ -149,6 +149,14 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie } } + public void flagDisableInputs() { + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + } + + public void flagEnableInputs() { + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + } + public void flagScreenOn() { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } -- cgit v1.2.3