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

Commit

Permalink
Add internal playback of audio files
Browse files Browse the repository at this point in the history
Signed-off-by: Manuel Stahl <[email protected]>
Change-Id: If753ce84a66d5c1ac5d176267dccb16c147cf6de
  • Loading branch information
awesome-manuel committed Sep 17, 2019
1 parent 6fe8099 commit 4343a9a
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 8 deletions.
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ MatrixSdk:
- Changelog: https://github.com/matrix-org/matrix-android-sdk/releases/tag/v0.X.Y

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

Improvements:
-
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

0 comments on commit 4343a9a

Please sign in to comment.