AudioPlayer: disable screen and switch to earpiece when holding phone to ear
Based of initial worked by @harshitbansal05
This commit is contained in:
parent
f533e526fb
commit
06f37b0d2b
|
@ -0,0 +1,16 @@
|
||||||
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
public class MediaPlayer extends android.media.MediaPlayer {
|
||||||
|
|
||||||
|
private int streamType;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAudioStreamType(int streamType) {
|
||||||
|
this.streamType = streamType;
|
||||||
|
super.setAudioStreamType(streamType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAudioStreamType() {
|
||||||
|
return streamType;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1771,6 +1771,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
|
messageListAdapter.unregisterListenerInAudioPlayer();
|
||||||
if (activity == null || !activity.isChangingConfigurations()) {
|
if (activity == null || !activity.isChangingConfigurations()) {
|
||||||
hideSoftKeyboard(activity);
|
hideSoftKeyboard(activity);
|
||||||
messageListAdapter.stopAudioPlayer();
|
messageListAdapter.stopAudioPlayer();
|
||||||
|
|
|
@ -877,6 +877,10 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
|
||||||
audioPlayer.stop();
|
audioPlayer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unregisterListenerInAudioPlayer() {
|
||||||
|
audioPlayer.unregisterListener();
|
||||||
|
}
|
||||||
|
|
||||||
public void startStopPending() {
|
public void startStopPending() {
|
||||||
audioPlayer.startStopPending();
|
audioPlayer.startStopPending();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
package eu.siacs.conversations.ui.service;
|
package eu.siacs.conversations.ui.service;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.media.MediaPlayer;
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
import android.media.AudioManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.PowerManager;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
|
@ -17,14 +24,16 @@ import android.widget.TextView;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
import eu.siacs.conversations.services.MediaPlayer;
|
||||||
import eu.siacs.conversations.ui.ConversationsActivity;
|
import eu.siacs.conversations.ui.ConversationsActivity;
|
||||||
import eu.siacs.conversations.ui.adapter.MessageAdapter;
|
import eu.siacs.conversations.ui.adapter.MessageAdapter;
|
||||||
import eu.siacs.conversations.ui.util.PendingItem;
|
import eu.siacs.conversations.ui.util.PendingItem;
|
||||||
import eu.siacs.conversations.utils.WeakReferenceSet;
|
import eu.siacs.conversations.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 int REFRESH_INTERVAL = 250;
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
|
@ -32,16 +41,36 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
private static Message currentlyPlayingMessage = null;
|
private static Message currentlyPlayingMessage = null;
|
||||||
private final MessageAdapter messageAdapter;
|
private final MessageAdapter messageAdapter;
|
||||||
private final WeakReferenceSet<RelativeLayout> audioPlayerLayouts = new WeakReferenceSet<>();
|
private final WeakReferenceSet<RelativeLayout> audioPlayerLayouts = new WeakReferenceSet<>();
|
||||||
|
private final SensorManager sensorManager;
|
||||||
|
private final Sensor proximitySensor;
|
||||||
|
private static PowerManager.WakeLock wakeLock;
|
||||||
|
|
||||||
private final PendingItem<WeakReference<ImageButton>> pendingOnClickView = new PendingItem<>();
|
private final PendingItem<WeakReference<ImageButton>> pendingOnClickView = new PendingItem<>();
|
||||||
|
|
||||||
private final Handler handler = new Handler();
|
private final Handler handler = new Handler();
|
||||||
|
|
||||||
public AudioPlayer(MessageAdapter adapter) {
|
public AudioPlayer(MessageAdapter adapter) {
|
||||||
|
final Context context = adapter.getContext();
|
||||||
this.messageAdapter = adapter;
|
this.messageAdapter = adapter;
|
||||||
|
this.sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||||
|
this.proximitySensor = this.sensorManager == null ? null : this.sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
synchronized (AudioPlayer.LOCK) {
|
||||||
|
if (AudioPlayer.wakeLock == null) {
|
||||||
|
final PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||||
|
AudioPlayer.wakeLock = powerManager == null ? null : powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, AudioPlayer.class.getSimpleName());
|
||||||
|
AudioPlayer.wakeLock.setReferenceCounted(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AudioPlayer.wakeLock = null;
|
||||||
|
}
|
||||||
synchronized (AudioPlayer.LOCK) {
|
synchronized (AudioPlayer.LOCK) {
|
||||||
if (AudioPlayer.player != null) {
|
if (AudioPlayer.player != null) {
|
||||||
AudioPlayer.player.setOnCompletionListener(this);
|
AudioPlayer.player.setOnCompletionListener(this);
|
||||||
|
if (AudioPlayer.player.isPlaying() && sensorManager != null) {
|
||||||
|
sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,32 +154,45 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
viewHolder.progress.setEnabled(false);
|
viewHolder.progress.setEnabled(false);
|
||||||
player.pause();
|
player.pause();
|
||||||
messageAdapter.flagScreenOff();
|
messageAdapter.flagScreenOff();
|
||||||
|
releaseProximityWakeLock();
|
||||||
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
|
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
|
||||||
} else {
|
} else {
|
||||||
viewHolder.progress.setEnabled(true);
|
viewHolder.progress.setEnabled(true);
|
||||||
player.start();
|
player.start();
|
||||||
messageAdapter.flagScreenOn();
|
messageAdapter.flagScreenOn();
|
||||||
|
acquireProximityWakeLock();
|
||||||
this.stopRefresher(true);
|
this.stopRefresher(true);
|
||||||
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
|
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean play(ViewHolder viewHolder, Message message) {
|
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 MediaPlayer();
|
AudioPlayer.player = new MediaPlayer();
|
||||||
try {
|
try {
|
||||||
AudioPlayer.currentlyPlayingMessage = message;
|
AudioPlayer.currentlyPlayingMessage = message;
|
||||||
|
AudioPlayer.player.setAudioStreamType(earpiece ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC);
|
||||||
AudioPlayer.player.setDataSource(messageAdapter.getFileBackend().getFile(message).getAbsolutePath());
|
AudioPlayer.player.setDataSource(messageAdapter.getFileBackend().getFile(message).getAbsolutePath());
|
||||||
AudioPlayer.player.setOnCompletionListener(this);
|
AudioPlayer.player.setOnCompletionListener(this);
|
||||||
AudioPlayer.player.prepare();
|
AudioPlayer.player.prepare();
|
||||||
AudioPlayer.player.start();
|
AudioPlayer.player.start();
|
||||||
messageAdapter.flagScreenOn();
|
messageAdapter.flagScreenOn();
|
||||||
|
acquireProximityWakeLock();
|
||||||
viewHolder.progress.setEnabled(true);
|
viewHolder.progress.setEnabled(true);
|
||||||
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
|
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;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
messageAdapter.flagScreenOff();
|
messageAdapter.flagScreenOff();
|
||||||
|
releaseProximityWakeLock();
|
||||||
AudioPlayer.currentlyPlayingMessage = null;
|
AudioPlayer.currentlyPlayingMessage = null;
|
||||||
|
sensorManager.unregisterListener(this);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +214,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
if (AudioPlayer.player != null) {
|
if (AudioPlayer.player != null) {
|
||||||
stopCurrent();
|
stopCurrent();
|
||||||
}
|
}
|
||||||
return play(viewHolder, message);
|
return play(viewHolder, message, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopCurrent() {
|
private void stopCurrent() {
|
||||||
|
@ -181,6 +223,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
}
|
}
|
||||||
AudioPlayer.player.release();
|
AudioPlayer.player.release();
|
||||||
messageAdapter.flagScreenOff();
|
messageAdapter.flagScreenOff();
|
||||||
|
releaseProximityWakeLock();
|
||||||
AudioPlayer.player = null;
|
AudioPlayer.player = null;
|
||||||
resetPlayerUi();
|
resetPlayerUi();
|
||||||
}
|
}
|
||||||
|
@ -206,7 +249,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCompletion(MediaPlayer mediaPlayer) {
|
public void onCompletion(android.media.MediaPlayer mediaPlayer) {
|
||||||
synchronized (AudioPlayer.LOCK) {
|
synchronized (AudioPlayer.LOCK) {
|
||||||
this.stopRefresher(false);
|
this.stopRefresher(false);
|
||||||
if (AudioPlayer.player == mediaPlayer) {
|
if (AudioPlayer.player == mediaPlayer) {
|
||||||
|
@ -215,7 +258,9 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
}
|
}
|
||||||
mediaPlayer.release();
|
mediaPlayer.release();
|
||||||
messageAdapter.flagScreenOff();
|
messageAdapter.flagScreenOff();
|
||||||
|
releaseProximityWakeLock();
|
||||||
resetPlayerUi();
|
resetPlayerUi();
|
||||||
|
sensorManager.unregisterListener(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +295,11 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
stopCurrent();
|
stopCurrent();
|
||||||
}
|
}
|
||||||
AudioPlayer.currentlyPlayingMessage = null;
|
AudioPlayer.currentlyPlayingMessage = null;
|
||||||
|
sensorManager.unregisterListener(this);
|
||||||
|
if (wakeLock != null && wakeLock.isHeld()) {
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
wakeLock = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +310,12 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unregisterListener() {
|
||||||
|
if (sensorManager != null) {
|
||||||
|
sensorManager.unregisterListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (AudioPlayer.LOCK) {
|
synchronized (AudioPlayer.LOCK) {
|
||||||
|
@ -287,6 +343,70 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
return true;
|
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) {
|
||||||
|
play(currentViewHolder, currentlyPlayingMessage, streamType == AudioManager.STREAM_VOICE_CALL, progress);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(Config.LOGTAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccuracyChanged(Sensor sensor, int i) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acquireProximityWakeLock() {
|
||||||
|
synchronized (AudioPlayer.LOCK) {
|
||||||
|
if (wakeLock != null) {
|
||||||
|
wakeLock.acquire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseProximityWakeLock() {
|
||||||
|
synchronized (AudioPlayer.LOCK) {
|
||||||
|
if (wakeLock != null && wakeLock.isHeld()) {
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ViewHolder getCurrentViewHolder() {
|
||||||
|
for (WeakReference<RelativeLayout> audioPlayer : audioPlayerLayouts) {
|
||||||
|
final Message message = (Message) audioPlayer.get().getTag();
|
||||||
|
if (message == currentlyPlayingMessage) {
|
||||||
|
return ViewHolder.get(audioPlayer.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static class ViewHolder {
|
public static class ViewHolder {
|
||||||
private TextView runtime;
|
private TextView runtime;
|
||||||
private SeekBar progress;
|
private SeekBar progress;
|
||||||
|
@ -297,9 +417,9 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
|
||||||
ViewHolder viewHolder = (ViewHolder) audioPlayer.getTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER);
|
ViewHolder viewHolder = (ViewHolder) audioPlayer.getTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER);
|
||||||
if (viewHolder == null) {
|
if (viewHolder == null) {
|
||||||
viewHolder = new ViewHolder();
|
viewHolder = new ViewHolder();
|
||||||
viewHolder.runtime = (TextView) audioPlayer.findViewById(R.id.runtime);
|
viewHolder.runtime = audioPlayer.findViewById(R.id.runtime);
|
||||||
viewHolder.progress = (SeekBar) audioPlayer.findViewById(R.id.progress);
|
viewHolder.progress = audioPlayer.findViewById(R.id.progress);
|
||||||
viewHolder.playPause = (ImageButton) audioPlayer.findViewById(R.id.play_pause);
|
viewHolder.playPause = audioPlayer.findViewById(R.id.play_pause);
|
||||||
audioPlayer.setTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER, viewHolder);
|
audioPlayer.setTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER, viewHolder);
|
||||||
}
|
}
|
||||||
return viewHolder;
|
return viewHolder;
|
||||||
|
|
Loading…
Reference in a new issue