Single instance embedded music player

pull/214/head
M66B 8 months ago
parent b673256c25
commit e4871a5170

@ -28,13 +28,10 @@ import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.pdf.PdfRenderer; import android.graphics.pdf.PdfRenderer;
import android.media.AudioAttributes;
import android.media.MediaPlayer;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -95,10 +92,10 @@ public class AdapterMedia extends RecyclerView.Adapter<AdapterMedia.ViewHolder>
} }
private void showPlayerState(EntityAttachment attachment) { private void showPlayerState(EntityAttachment attachment) {
if (attachment.player == null) if (MediaPlayerHelper.isPlaying(attachment.getUri(context)))
ivImage.setImageResource(R.drawable.twotone_play_arrow_48);
else
ivImage.setImageResource(R.drawable.twotone_stop_48); ivImage.setImageResource(R.drawable.twotone_stop_48);
else
ivImage.setImageResource(R.drawable.twotone_play_arrow_48);
} }
private void bindTo(EntityAttachment attachment) { private void bindTo(EntityAttachment attachment) {
@ -262,57 +259,20 @@ public class AdapterMedia extends RecyclerView.Adapter<AdapterMedia.ViewHolder>
if (attachment.available) { if (attachment.available) {
if (attachment.isAudio()) { if (attachment.isAudio()) {
try { try {
if (attachment.player == null) { Uri uri = attachment.getUri(context);
final Runnable updateTime = new Runnable() { if (MediaPlayerHelper.isPlaying(uri))
@Override MediaPlayerHelper.stopMusic(context);
public void run() { else
MediaPlayer player = attachment.player; MediaPlayerHelper.startMusic(context, uri,
tvProperties.setVisibility(player == null ? View.GONE : View.VISIBLE); new RunnableEx("player") {
if (player != null) { @Override
String pos = Helper.formatDuration(player.getCurrentPosition(), false); public void delegate() {
String duration = Helper.formatDuration(player.getDuration()); showPlayerState(attachment);
tvProperties.setText(pos + " / " + duration); }
view.postDelayed(this, 1000L); });
}
}
};
Uri uri = FileProviderEx.getUri(context, BuildConfig.APPLICATION_ID, attachment.getFile(context), attachment.name);
attachment.player = new MediaPlayer();
attachment.player.setAudioAttributes(
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build()
);
attachment.player.setDataSource(context, uri);
attachment.player.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);
attachment.player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
// https://issuetracker.google.com/issues/36921987
if (BuildConfig.DEBUG)
view.postDelayed(updateTime, 500L);
}
});
attachment.player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
attachment.player = null;
showPlayerState(attachment);
}
});
attachment.player.prepareAsync();
} else {
attachment.player.stop();
attachment.player = null;
}
showPlayerState(attachment); showPlayerState(attachment);
} catch (Throwable ex) { } catch (Throwable ex) {
attachment.player = null;
ivImage.setImageResource(R.drawable.twotone_warning_24); ivImage.setImageResource(R.drawable.twotone_warning_24);
Log.unexpectedError(parentFragment, ex); Log.unexpectedError(parentFragment, ex);
} }
@ -411,15 +371,7 @@ public class AdapterMedia extends RecyclerView.Adapter<AdapterMedia.ViewHolder>
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroyed() { public void onDestroyed() {
Log.d(AdapterMedia.this + " parent destroyed"); Log.d(AdapterMedia.this + " parent destroyed");
for (EntityAttachment attachment : items) MediaPlayerHelper.stopMusic(context);
if (attachment.player != null)
try {
attachment.player.stop();
} catch (Throwable ex) {
Log.w(ex);
} finally {
attachment.player = null;
}
AdapterMedia.this.parentFragment = null; AdapterMedia.this.parentFragment = null;
owner.getLifecycle().removeObserver(this); owner.getLifecycle().removeObserver(this);
} }

@ -102,9 +102,6 @@ public class EntityAttachment {
@Ignore @Ignore
public boolean selected = false; public boolean selected = false;
@Ignore
public MediaPlayer player = null;
// Gmail sends inline images as attachments with a name and cid // Gmail sends inline images as attachments with a name and cid
boolean isInline() { boolean isInline() {

@ -28,6 +28,7 @@ import android.media.AudioManager;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.PowerManager;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
@ -36,6 +37,7 @@ import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent; import androidx.lifecycle.OnLifecycleEvent;
import java.io.IOException; import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -46,6 +48,10 @@ public class MediaPlayerHelper {
private static Semaphore sem; private static Semaphore sem;
private static final Object lock = new Object(); private static final Object lock = new Object();
private static MediaPlayer player = null;
private static Uri uri = null;
private static Runnable onCompleted = null;
static void stop(Context context) { static void stop(Context context) {
EntityLog.log(context, "Alarm stop"); EntityLog.log(context, "Alarm stop");
synchronized (lock) { synchronized (lock) {
@ -155,6 +161,63 @@ public class MediaPlayerHelper {
} }
} }
static void startMusic(Context context, Uri uri, Runnable onCompleted) throws IOException {
stopMusic(context);
synchronized (lock) {
MediaPlayerHelper.uri = uri;
MediaPlayerHelper.onCompleted = onCompleted;
MediaPlayerHelper.player = new MediaPlayer();
MediaPlayerHelper.player.setAudioAttributes(
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build()
);
MediaPlayerHelper.player.setDataSource(context, uri);
MediaPlayerHelper.player.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);
MediaPlayerHelper.player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// https://issuetracker.google.com/issues/36921987
mp.start();
}
});
MediaPlayerHelper.player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
stopMusic(context);
}
});
MediaPlayerHelper.player.prepareAsync();
}
}
static void stopMusic(Context context) {
synchronized (lock) {
if (MediaPlayerHelper.player != null)
try {
MediaPlayerHelper.player.stop();
} catch (Throwable ex) {
Log.e(ex);
} finally {
MediaPlayerHelper.player = null;
}
MediaPlayerHelper.uri = null;
if (MediaPlayerHelper.onCompleted != null) {
MediaPlayerHelper.onCompleted.run();
MediaPlayerHelper.onCompleted = null;
}
}
}
static boolean isPlaying(Uri uri) {
synchronized (lock) {
return (Objects.equals(MediaPlayerHelper.uri, uri));
}
}
static void liveInCall(Context context, LifecycleOwner owner, IInCall intf) { static void liveInCall(Context context, LifecycleOwner owner, IInCall intf) {
AudioManager am = Helper.getSystemService(context, AudioManager.class); AudioManager am = Helper.getSystemService(context, AudioManager.class);
if (am == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { if (am == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {

Loading…
Cancel
Save