Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit c0807ab

Browse files
Add internal playback of audio files
Signed-off-by: Manuel Stahl <manuel.stahl@awesome-technologies.de>
1 parent f23e9d8 commit c0807ab

9 files changed

+249
-7
lines changed

vector/src/main/java/im/vector/adapters/VectorMessagesAdapter.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import android.graphics.Point;
2525
import android.graphics.Typeface;
2626
import android.graphics.drawable.Drawable;
27+
import android.media.MediaPlayer;
2728
import android.os.Build;
2829
import android.os.Handler;
2930
import android.os.Looper;
@@ -882,6 +883,8 @@ public void onBingRulesUpdate() {
882883
*/
883884
public void onPause() {
884885
mEventFormattedTsMap.clear();
886+
887+
mMediasHelper.refreshPlayImageViews();
885888
}
886889

887890
/**
@@ -951,9 +954,9 @@ public Event getCurrentSelectedEvent() {
951954
*
952955
* @param listener teh events listener
953956
*/
954-
public void setVectorMessagesAdapterActionsListener(IMessagesAdapterActionsListener listener) {
957+
public void setVectorMessagesAdapterActionsListener(IMessagesAdapterActionsListener listener, HashMap<String, MediaPlayer> mediaPlayers) {
955958
mVectorMessagesAdapterEventsListener = listener;
956-
mMediasHelper.setVectorMessagesAdapterActionsListener(listener);
959+
mMediasHelper.setVectorMessagesAdapterActionsListener(listener, mediaPlayers);
957960
mHelper.setVectorMessagesAdapterActionsListener(listener);
958961

959962
if (null != mLinkMovementMethod) {
@@ -1589,6 +1592,7 @@ private View getFileView(final int position, View convertView, ViewGroup parent)
15891592

15901593
mMediasHelper.managePendingFileDownload(convertView, event, fileMessage, position);
15911594
mMediasHelper.managePendingUpload(convertView, event, ROW_TYPE_FILE, fileMessage.url);
1595+
mMediasHelper.managePlayback(convertView, event, ROW_TYPE_FILE, fileMessage.url);
15921596

15931597
View fileLayout = convertView.findViewById(R.id.messagesAdapter_file_layout);
15941598
manageSubView(position, convertView, fileLayout, ROW_TYPE_FILE);

vector/src/main/java/im/vector/adapters/VectorMessagesAdapterMediasHelper.java

+73-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import android.content.Context;
2121
import android.graphics.Color;
2222
import android.media.ExifInterface;
23+
import android.media.MediaPlayer;
24+
import android.os.Handler;
2325
import android.text.TextUtils;
2426
import android.text.format.DateUtils;
2527
import android.view.View;
@@ -75,6 +77,10 @@ class VectorMessagesAdapterMediasHelper {
7577
private final int mNotSentMessageTextColor;
7678
private final int mDefaultMessageTextColor;
7779

80+
private final Handler handler = new Handler();
81+
private HashMap<String, ImageView> mPlayImageViews = new HashMap<>();
82+
private HashMap<String, MediaPlayer> mMediaPlayers;
83+
7884
VectorMessagesAdapterMediasHelper(Context context,
7985
MXSession session,
8086
int maxImageWidth,
@@ -96,8 +102,9 @@ class VectorMessagesAdapterMediasHelper {
96102
*
97103
* @param listener teh events listener
98104
*/
99-
void setVectorMessagesAdapterActionsListener(IMessagesAdapterActionsListener listener) {
105+
void setVectorMessagesAdapterActionsListener(IMessagesAdapterActionsListener listener, HashMap<String, MediaPlayer> mediaPlayers) {
100106
mVectorMessagesAdapterEventsListener = listener;
107+
mMediaPlayers = mediaPlayers;
101108
}
102109

103110
/**
@@ -180,6 +187,71 @@ public void onUploadComplete(final String uploadId, final String contentUri) {
180187
refreshUploadViews(event, uploadStats, uploadProgressLayout);
181188
}
182189

190+
void managePlayback(final View convertView, final Event event, final int type, final String mediaUrl) {
191+
View playbackLayout = convertView.findViewById(R.id.content_media_playback_layout);
192+
playbackLayout.setTag(mediaUrl);
193+
final View playButton = playbackLayout.findViewById(R.id.media_playback);
194+
195+
if (null == playButton) return;
196+
197+
playButton.setTag(event);
198+
playButton.setOnClickListener(new View.OnClickListener() {
199+
@Override
200+
public void onClick(View v) {
201+
if ((event == playButton.getTag()) && (null != mVectorMessagesAdapterEventsListener)) {
202+
ImageView imageView = playButton.findViewById(R.id.media_play_icon);
203+
if ((null != imageView.getTag()) && (imageView.getTag().equals("playing"))) {
204+
mVectorMessagesAdapterEventsListener.onEventAction(event, "", R.id.ic_action_pause_audio);
205+
imageView.setImageResource(R.drawable.ic_baseline_play_arrow_24px);
206+
imageView.setTag("paused");
207+
} else {
208+
mVectorMessagesAdapterEventsListener.onEventAction(event, "", R.id.ic_action_play_audio);
209+
imageView.setTag("playing");
210+
if (!mPlayImageViews.containsKey(mediaUrl)) {
211+
mPlayImageViews.put(mediaUrl, imageView);
212+
}
213+
refreshPlayImageViews();
214+
imageView.setImageResource(R.drawable.ic_baseline_pause_24px);
215+
final ProgressBar progressBar = playbackLayout.findViewById(R.id.media_progress_view);
216+
refreshPlaybackProgress(progressBar, mediaUrl);
217+
}
218+
}
219+
}
220+
});
221+
}
222+
223+
void refreshPlayImageViews() {
224+
for (ImageView iv : mPlayImageViews.values()) {
225+
iv.setImageResource(R.drawable.ic_baseline_play_arrow_24px);
226+
}
227+
}
228+
229+
void refreshPlaybackProgress(ProgressBar progressBar, String mediaUrl) {
230+
handler.postDelayed(new Runnable() {
231+
@Override
232+
public void run() {
233+
if (null == mMediaPlayers) {
234+
return;
235+
}
236+
try {
237+
MediaPlayer mediaPlayer = mMediaPlayers.get(mediaUrl);
238+
239+
if (mediaPlayer == null || mediaUrl == null)
240+
return;
241+
242+
progressBar.setProgress((int) ((float) mediaPlayer.getCurrentPosition() / mediaPlayer.getDuration() * progressBar.getMax()));
243+
if (mediaPlayer.isPlaying()) {
244+
refreshPlaybackProgress(progressBar, mediaUrl);
245+
} else {
246+
mPlayImageViews.get(mediaUrl).setImageResource(R.drawable.ic_baseline_play_arrow_24px);
247+
}
248+
} catch (Exception e) {
249+
e.printStackTrace();
250+
}
251+
}
252+
}, 1000);
253+
}
254+
183255
// the image / video bitmaps are set to null if the matching URL is not the same
184256
// to avoid flickering
185257
private Map<String, String> mUrlByBitmapIndex = new HashMap<>();

vector/src/main/java/im/vector/fragments/VectorMessageListFragment.java

+78-4
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@
2020

2121
import android.annotation.SuppressLint;
2222
import android.app.Activity;
23+
import android.content.BroadcastReceiver;
24+
import android.content.Context;
2325
import android.content.DialogInterface;
2426
import android.content.Intent;
27+
import android.content.IntentFilter;
28+
import android.media.AudioManager;
29+
import android.media.MediaPlayer;
2530
import android.net.Uri;
2631
import android.os.Bundle;
2732
import android.support.annotation.NonNull;
@@ -30,6 +35,7 @@
3035
import android.support.v4.content.FileProvider;
3136
import android.support.v7.app.AlertDialog;
3237
import android.text.TextUtils;
38+
import android.util.Base64;
3339
import android.view.LayoutInflater;
3440
import android.view.MotionEvent;
3541
import android.view.View;
@@ -69,7 +75,10 @@
6975
import org.matrix.androidsdk.rest.model.message.Message;
7076
import org.matrix.androidsdk.rest.model.message.VideoMessage;
7177

78+
import java.io.BufferedInputStream;
7279
import java.io.File;
80+
import java.io.FileInputStream;
81+
import java.io.IOException;
7382
import java.util.ArrayList;
7483
import java.util.Collections;
7584
import java.util.HashMap;
@@ -109,8 +118,22 @@ public class VectorMessageListFragment extends MatrixMessageListFragment<VectorM
109118
private String mPendingFilename;
110119
private EncryptedFileInfo mPendingEncryptedFileInfo;
111120

121+
private IntentFilter mBecomingNoisyIntentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
122+
private BroadcastReceiver mBecomingNoisyReceiver = new BroadcastReceiver() {
123+
@Override
124+
public void onReceive(Context context, Intent intent) {
125+
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
126+
for (MediaPlayer mp : mMediaPlayers.values()) {
127+
mp.pause();
128+
}
129+
}
130+
}
131+
};
132+
112133
private static int VERIF_REQ_CODE = 12;
113134

135+
private HashMap<String, MediaPlayer> mMediaPlayers;
136+
114137
public interface VectorMessageListFragmentListener {
115138
/**
116139
* Display a spinner to warn the user that a back pagination is in progress.
@@ -216,6 +239,8 @@ public void onItemClick(AdapterView<?> parent, View view, int position, long id)
216239
}
217240
});
218241

242+
mMediaPlayers = new HashMap<>();
243+
219244
v.setBackgroundColor(ThemeUtils.INSTANCE.getColor(getActivity(), android.R.attr.colorBackground));
220245

221246
return v;
@@ -247,7 +272,11 @@ protected String getMatrixMessagesFragmentTag() {
247272
public void onPause() {
248273
super.onPause();
249274

250-
mAdapter.setVectorMessagesAdapterActionsListener(null);
275+
for (MediaPlayer mediaPlayer : mMediaPlayers.values()) {
276+
mediaPlayer.pause();
277+
}
278+
getContext().unregisterReceiver(mBecomingNoisyReceiver);
279+
mAdapter.setVectorMessagesAdapterActionsListener(null, mMediaPlayers);
251280
mAdapter.onPause();
252281

253282
mVectorImageGetter.setListener(null);
@@ -258,7 +287,8 @@ public void onPause() {
258287
public void onResume() {
259288
super.onResume();
260289

261-
mAdapter.setVectorMessagesAdapterActionsListener(this);
290+
getContext().registerReceiver(mBecomingNoisyReceiver, mBecomingNoisyIntentFilter);
291+
mAdapter.setVectorMessagesAdapterActionsListener(this, mMediaPlayers);
262292

263293
mVectorImageGetter.setListener(new VectorImageGetter.OnImageDownloadListener() {
264294
@Override
@@ -751,6 +781,20 @@ public void onDismiss(DialogInterface dialog) {
751781
}
752782
})
753783
.show();
784+
} else if (action == R.id.ic_action_play_audio) {
785+
Message message = JsonUtils.toMessage(event.getContent());
786+
FileMessage fileMessage = JsonUtils.toFileMessage(event.getContent());
787+
788+
if (null != fileMessage.getUrl()) {
789+
onMediaAction(ACTION_VECTOR_OPEN, fileMessage.getUrl(), fileMessage.getMimeType(), fileMessage.body, fileMessage.file);
790+
}
791+
} else if (action == R.id.ic_action_pause_audio) {
792+
Message message = JsonUtils.toMessage(event.getContent());
793+
FileMessage fileMessage = JsonUtils.toFileMessage(event.getContent());
794+
795+
if (null != fileMessage.getUrl() && mMediaPlayers.containsKey(fileMessage.getUrl())) {
796+
mMediaPlayers.get(fileMessage.getUrl()).pause();
797+
}
754798
}
755799
}
756800

@@ -893,7 +937,37 @@ public void onSuccess(File file) {
893937
return;
894938
}
895939

896-
if (menuAction == ACTION_VECTOR_SAVE || menuAction == ACTION_VECTOR_OPEN) {
940+
if (menuAction == ACTION_VECTOR_OPEN && mediaMimeType.startsWith("audio/")) {
941+
Log.e(LOG_TAG, "Using Media player " + file.getAbsolutePath());
942+
943+
for (MediaPlayer mp : mMediaPlayers.values()) {
944+
mp.pause();
945+
}
946+
947+
MediaPlayer mediaPlayer;
948+
if (!mMediaPlayers.containsKey(mediaUrl)) {
949+
mediaPlayer = new MediaPlayer();
950+
mMediaPlayers.put(mediaUrl, mediaPlayer);
951+
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
952+
try {
953+
int size = (int) file.length();
954+
byte[] callData = new byte[size];
955+
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
956+
buf.read(callData, 0, callData.length);
957+
buf.close();
958+
String base64EncodedString = Base64.encodeToString(callData, Base64.DEFAULT);
959+
960+
String url = "data:audio/amr;base64," + base64EncodedString;
961+
mediaPlayer.setDataSource(url);
962+
mediaPlayer.prepare();
963+
} catch (IOException e) {
964+
e.printStackTrace();
965+
}
966+
} else {
967+
mediaPlayer = mMediaPlayers.get(mediaUrl);
968+
}
969+
mediaPlayer.start();
970+
} else if (menuAction == ACTION_VECTOR_SAVE || menuAction == ACTION_VECTOR_OPEN) {
897971
if (PermissionsToolsKt.checkPermissions(PermissionsToolsKt.PERMISSIONS_FOR_WRITING_FILES,
898972
VectorMessageListFragment.this, PermissionsToolsKt.PERMISSION_REQUEST_CODE)) {
899973
CommonActivityUtils.saveMediaIntoDownloads(getActivity(), file, trimmedFileName, mediaMimeType, new SimpleApiCallback<String>() {
@@ -1151,7 +1225,7 @@ public void onContentClick(int position) {
11511225

11521226
getActivity().startActivity(viewImageIntent);
11531227
}
1154-
} else if (Message.MSGTYPE_FILE.equals(message.msgtype) || Message.MSGTYPE_AUDIO.equals(message.msgtype)) {
1228+
} else if (Message.MSGTYPE_FILE.equals(message.msgtype)) {
11551229
FileMessage fileMessage = JsonUtils.toFileMessage(event.getContent());
11561230

11571231
if (null != fileMessage.getUrl()) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
9+
</vector>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M8,5v14l11,-7z"/>
9+
</vector>

vector/src/main/res/layout/adapter_item_vector_message_file.xml

+10
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,16 @@
156156

157157
</RelativeLayout>
158158

159+
<RelativeLayout
160+
android:layout_width="match_parent"
161+
android:layout_height="wrap_content">
162+
163+
<include
164+
android:id="@+id/content_media_playback_layout"
165+
layout="@layout/media_playback_control" />
166+
167+
</RelativeLayout>
168+
159169
</LinearLayout>
160170

161171
</LinearLayout>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
android:layout_width="match_parent"
5+
android:layout_height="wrap_content"
6+
android:baselineAligned="false"
7+
android:orientation="horizontal">
8+
9+
<LinearLayout
10+
android:layout_width="0dp"
11+
android:layout_height="wrap_content"
12+
android:layout_weight="1"
13+
android:orientation="vertical">
14+
15+
<TextView
16+
android:id="@+id/media_progress_text_view"
17+
android:layout_width="wrap_content"
18+
android:layout_height="wrap_content"
19+
android:layout_marginTop="10dp"
20+
android:textSize="10sp"
21+
tools:text="Information" />
22+
23+
<ProgressBar
24+
android:id="@+id/media_progress_view"
25+
style="?android:attr/progressBarStyleHorizontal"
26+
android:layout_width="match_parent"
27+
android:layout_height="20dp"
28+
android:layout_gravity="center_vertical"
29+
android:max="100"
30+
android:progress="0"
31+
tools:progress="30" />
32+
33+
</LinearLayout>
34+
35+
<FrameLayout
36+
android:id="@+id/media_playback"
37+
android:layout_width="40dp"
38+
android:layout_height="match_parent">
39+
40+
<ImageView
41+
android:id="@+id/media_play_icon"
42+
android:layout_width="match_parent"
43+
android:layout_height="match_parent"
44+
android:layout_gravity="bottom|end"
45+
android:src="@drawable/ic_baseline_play_arrow_24px"
46+
android:tint="?attr/vctr_settings_icon_tint_color" />
47+
48+
</FrameLayout>
49+
50+
</LinearLayout>

0 commit comments

Comments
 (0)