Skip to content
This repository has been archived by the owner on Apr 12, 2022. It is now read-only.

Add internal playback of audio files #3207

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ MatrixSdk 🚀:
- Upgrade to version 0.X.Y.

Features ✨:
-
- Add internal playback of audio files (#3207)

Improvementss 🙌:
-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import android.graphics.Point;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
Expand Down Expand Up @@ -883,6 +884,7 @@ public void onBingRulesUpdate() {
*/
public void onPause() {
mEventFormattedTsMap.clear();
mMediasHelper.refreshPlayImageViews();
}

/**
Expand Down Expand Up @@ -952,9 +954,9 @@ public Event getCurrentSelectedEvent() {
*
* @param listener teh events listener
*/
public void setVectorMessagesAdapterActionsListener(IMessagesAdapterActionsListener listener) {
public void setVectorMessagesAdapterActionsListener(IMessagesAdapterActionsListener listener, Map<String, MediaPlayer> mediaPlayers) {
mVectorMessagesAdapterEventsListener = listener;
mMediasHelper.setVectorMessagesAdapterActionsListener(listener);
mMediasHelper.setVectorMessagesAdapterActionsListener(listener, mediaPlayers);
mHelper.setVectorMessagesAdapterActionsListener(listener);

if (null != mLinkMovementMethod) {
Expand Down Expand Up @@ -1590,6 +1592,7 @@ private View getFileView(final int position, View convertView, ViewGroup parent)

mMediasHelper.managePendingFileDownload(convertView, event, fileMessage, position);
mMediasHelper.managePendingUpload(convertView, event, ROW_TYPE_FILE, fileMessage.url);
mMediasHelper.managePlayback(convertView, event, ROW_TYPE_FILE, fileMessage.getUrl());

View fileLayout = convertView.findViewById(R.id.messagesAdapter_file_layout);
manageSubView(position, convertView, fileLayout, ROW_TYPE_FILE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import android.content.Context;
import android.graphics.Color;
import android.media.ExifInterface;
import android.media.MediaPlayer;
import android.os.Handler;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.View;
Expand Down Expand Up @@ -75,6 +77,10 @@ class VectorMessagesAdapterMediasHelper {
private final int mNotSentMessageTextColor;
private final int mDefaultMessageTextColor;

private final Handler handler = new Handler();
private Map<String, ImageView> mPlayImageViews = new HashMap<>();
private Map<String, MediaPlayer> mMediaPlayers;

VectorMessagesAdapterMediasHelper(Context context,
MXSession session,
int maxImageWidth,
Expand All @@ -96,8 +102,9 @@ class VectorMessagesAdapterMediasHelper {
*
* @param listener teh events listener
*/
void setVectorMessagesAdapterActionsListener(IMessagesAdapterActionsListener listener) {
void setVectorMessagesAdapterActionsListener(IMessagesAdapterActionsListener listener, Map<String, MediaPlayer> mediaPlayers) {
mVectorMessagesAdapterEventsListener = listener;
mMediaPlayers = mediaPlayers;
}

/**
Expand Down Expand Up @@ -180,6 +187,75 @@ public void onUploadComplete(final String uploadId, final String contentUri) {
refreshUploadViews(event, uploadStats, uploadProgressLayout);
}

void managePlayback(final View convertView, final Event event, final int type, final String mediaUrl) {
View playbackLayout = convertView.findViewById(R.id.content_media_playback_layout);
playbackLayout.setTag(mediaUrl);
final View playButton = playbackLayout.findViewById(R.id.media_playback);

if (null == playButton) return;

playButton.setTag(event);
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if ((event == playButton.getTag()) && (null != mVectorMessagesAdapterEventsListener)) {
ImageView imageView = playButton.findViewById(R.id.media_play_icon);
if ((null != imageView.getTag()) && (imageView.getTag().equals("playing"))) {
mVectorMessagesAdapterEventsListener.onEventAction(event, "", R.id.ic_action_pause_audio);
imageView.setImageResource(R.drawable.ic_baseline_play_arrow_24px);
imageView.setTag("paused");
} else {
mVectorMessagesAdapterEventsListener.onEventAction(event, "", R.id.ic_action_play_audio);
imageView.setTag("playing");
if (!mPlayImageViews.containsKey(mediaUrl)) {
mPlayImageViews.put(mediaUrl, imageView);
}
refreshPlayImageViews();
imageView.setImageResource(R.drawable.ic_baseline_pause_24px);
final ProgressBar progressBar = playbackLayout.findViewById(R.id.media_progress_view);
refreshPlaybackProgress(progressBar, mediaUrl);
}
}
}
});
}

void refreshPlayImageViews() {
for (ImageView iv : mPlayImageViews.values()) {
iv.setImageResource(R.drawable.ic_baseline_play_arrow_24px);
}
}

void refreshPlaybackProgress(ProgressBar progressBar, String mediaUrl) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (null == mMediaPlayers) {
return;
}
try {
MediaPlayer mediaPlayer = mMediaPlayers.get(mediaUrl);

if (mediaPlayer == null || mediaUrl == null) {
mPlayImageViews.get(mediaUrl).setImageResource(R.drawable.ic_baseline_play_arrow_24px);
progressBar.setProgress(0);
return;
}


progressBar.setProgress((int) ((float) mediaPlayer.getCurrentPosition() / mediaPlayer.getDuration() * progressBar.getMax()));
if (mediaPlayer.isPlaying()) {
refreshPlaybackProgress(progressBar, mediaUrl);
} else {
mPlayImageViews.get(mediaUrl).setImageResource(R.drawable.ic_baseline_play_arrow_24px);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, 1000);
}

// the image / video bitmaps are set to null if the matching URL is not the same
// to avoid flickering
private Map<String, String> mUrlByBitmapIndex = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Base64;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
Expand Down Expand Up @@ -70,7 +76,10 @@
import org.matrix.androidsdk.rest.model.message.Message;
import org.matrix.androidsdk.rest.model.message.VideoMessage;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -110,6 +119,19 @@ public class VectorMessageListFragment extends MatrixMessageListFragment<VectorM
private String mPendingFilename;
private EncryptedFileInfo mPendingEncryptedFileInfo;

private Map<String, MediaPlayer> mMediaPlayers = new HashMap<>();
private IntentFilter mBecomingNoisyIntentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private BroadcastReceiver mBecomingNoisyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
for (MediaPlayer mp : mMediaPlayers.values()) {
mp.pause();
}
}
}
};

private static int VERIF_REQ_CODE = 12;

public interface VectorMessageListFragmentListener {
Expand Down Expand Up @@ -248,18 +270,32 @@ protected String getMatrixMessagesFragmentTag() {
public void onPause() {
super.onPause();

mAdapter.setVectorMessagesAdapterActionsListener(null);
for (MediaPlayer mediaPlayer : mMediaPlayers.values()) {
mediaPlayer.pause();
}
getContext().unregisterReceiver(mBecomingNoisyReceiver);
mAdapter.setVectorMessagesAdapterActionsListener(null, mMediaPlayers);
mAdapter.onPause();

mVectorImageGetter.setListener(null);
}

@Override
public void onDestroy() {
super.onDestroy();

for (MediaPlayer mediaPlayer : mMediaPlayers.values()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}

@Override
public void onResume() {
super.onResume();

mAdapter.setVectorMessagesAdapterActionsListener(this);
getContext().registerReceiver(mBecomingNoisyReceiver, mBecomingNoisyIntentFilter);
mAdapter.setVectorMessagesAdapterActionsListener(this, mMediaPlayers);

mVectorImageGetter.setListener(new VectorImageGetter.OnImageDownloadListener() {
@Override
Expand Down Expand Up @@ -752,6 +788,20 @@ public void onDismiss(DialogInterface dialog) {
}
})
.show();
} else if (action == R.id.ic_action_play_audio) {
Message message = JsonUtils.toMessage(event.getContent());
FileMessage fileMessage = JsonUtils.toFileMessage(event.getContent());

if (null != fileMessage.getUrl()) {
onMediaAction(ACTION_VECTOR_OPEN, fileMessage.getUrl(), fileMessage.getMimeType(), fileMessage.body, fileMessage.file);
}
} else if (action == R.id.ic_action_pause_audio) {
Message message = JsonUtils.toMessage(event.getContent());
FileMessage fileMessage = JsonUtils.toFileMessage(event.getContent());

if (null != fileMessage.getUrl() && mMediaPlayers.containsKey(fileMessage.getUrl())) {
mMediaPlayers.get(fileMessage.getUrl()).pause();
}
}
}

Expand Down Expand Up @@ -894,7 +944,37 @@ public void onSuccess(File file) {
return;
}

if (menuAction == ACTION_VECTOR_SAVE || menuAction == ACTION_VECTOR_OPEN) {
if (menuAction == ACTION_VECTOR_OPEN && mediaMimeType.startsWith("audio/")) {
Log.e(LOG_TAG, "Using Media player " + file.getAbsolutePath());

for (MediaPlayer mp : mMediaPlayers.values()) {
mp.pause();
}

MediaPlayer mediaPlayer;
if (!mMediaPlayers.containsKey(mediaUrl)) {
mediaPlayer = new MediaPlayer();
mMediaPlayers.put(mediaUrl, mediaPlayer);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
int size = (int) file.length();
byte[] callData = new byte[size];
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
buf.read(callData, 0, callData.length);
buf.close();
String base64EncodedString = Base64.encodeToString(callData, Base64.DEFAULT);

String url = "data:audio/amr;base64," + base64EncodedString;
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
} else {
mediaPlayer = mMediaPlayers.get(mediaUrl);
}
mediaPlayer.start();
} else if (menuAction == ACTION_VECTOR_SAVE || menuAction == ACTION_VECTOR_OPEN) {
if (PermissionsToolsKt.checkPermissions(PermissionsToolsKt.PERMISSIONS_FOR_WRITING_FILES,
VectorMessageListFragment.this, PermissionsToolsKt.PERMISSION_REQUEST_CODE)) {
CommonActivityUtils.saveMediaIntoDownloads(getActivity(), file, trimmedFileName, mediaMimeType, new SimpleApiCallback<String>() {
Expand Down Expand Up @@ -1152,7 +1232,7 @@ public void onContentClick(int position) {

getActivity().startActivity(viewImageIntent);
}
} else if (Message.MSGTYPE_FILE.equals(message.msgtype) || Message.MSGTYPE_AUDIO.equals(message.msgtype)) {
} else if (Message.MSGTYPE_FILE.equals(message.msgtype)) {
FileMessage fileMessage = JsonUtils.toFileMessage(event.getContent());

if (null != fileMessage.getUrl()) {
Expand Down
9 changes: 9 additions & 0 deletions vector/src/main/res/drawable/ic_baseline_pause_24px.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>
9 changes: 9 additions & 0 deletions vector/src/main/res/drawable/ic_baseline_play_arrow_24px.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M8,5v14l11,-7z"/>
</vector>
10 changes: 10 additions & 0 deletions vector/src/main/res/layout/adapter_item_vector_message_file.xml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,16 @@

</RelativeLayout>

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<include
android:id="@+id/content_media_playback_layout"
layout="@layout/media_playback_control" />

</RelativeLayout>

</LinearLayout>

</LinearLayout>
Expand Down
50 changes: 50 additions & 0 deletions vector/src/main/res/layout/media_playback_control.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal">

<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">

<TextView
android:id="@+id/media_progress_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textSize="10sp"
tools:text="Information" />

<ProgressBar
android:id="@+id/media_progress_view"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_gravity="center_vertical"
android:max="100"
android:progress="0"
tools:progress="30" />

</LinearLayout>

<FrameLayout
android:id="@+id/media_playback"
android:layout_width="40dp"
android:layout_height="match_parent">

<ImageView
android:id="@+id/media_play_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom|end"
android:src="@drawable/ic_baseline_play_arrow_24px"
android:tint="?attr/vctr_settings_icon_tint_color" />

</FrameLayout>

</LinearLayout>
Loading