Recording audio file is now supported.

This commit is contained in:
Lyndon
2017-11-24 13:52:05 +01:00
parent 13ca4972bf
commit bebbb845c1
21 changed files with 132 additions and 82 deletions

View File

@@ -34,8 +34,8 @@ android {
applicationId "de.beyondsoft.ownchat"
minSdkVersion 19
targetSdkVersion 26
versionCode 6
versionName "1.6"
versionCode 7
versionName "1.7"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
@@ -111,7 +111,7 @@ dependencies {
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'de.hdodenhof:circleimageview:2.1.0'
compile 'com.scottyab:secure-preferences-lib:0.1.4'
compile 'com.google.firebase:firebase-messaging:11.4.2'
compile 'com.google.firebase:firebase-messaging:11.6.0'
compile 'hani.momanii.supernova_emoji_library:supernova-emoji-library:0.0.2'
compile 'com.github.lzyzsd:circleprogress:1.2.1'
compile 'org.greenrobot:eventbus:3.0.0'
@@ -136,4 +136,4 @@ task adp2upload(type: Exec, dependsOn: "build") {
commandLine 'upload_build.sh', "-c", "$channel", "-v", "$versionCode", "-p", "android", "-a", "$slug", "-f", "$file", "-i", "$identifier", "-n", "$notes"
}
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.gms.google-services'

View File

@@ -68,6 +68,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
@@ -347,7 +348,6 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
private int xDelta;
private String mAudioFilePath;
private Rect mRecButtonRightLimit;
private int mMaxMarginRight;
private Rect mDialogContainer;
private void selectFile(int requestCode) {
@@ -368,6 +368,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
ImageView attachDocumentImageView = dialog.findViewById(R.id.attachDocumentBtn);
TouchableImageView attachRecordAudioImageView = dialog.findViewById(R.id.attachRecordAudioBtn);
TextView limitTextView = dialog.findViewById(R.id.audioRecordingLimitTextView);
ImageView abortRecordingImageView = dialog.findViewById(R.id.abortRecordingImageView);
attachDocumentImageView.setOnClickListener(v -> {
FilePickerBuilder.getInstance().setMaxCount(1)
@@ -395,16 +396,20 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
});
dialog.setOnShowListener(dialog1 -> {
mRecButtonRightLimit = ViewUtils.getRectFromView(attachRecordAudioImageView);
mMaxMarginRight = ((GridLayout.LayoutParams) attachRecordAudioImageView.getLayoutParams()).leftMargin;
mDialogContainer = ViewUtils.getRectFromView(dialog.findViewById(R.id.dialogGridLayout));
});
final long duration = (mUploadMaxSize.get() / 256000L) * 1000;
Log.d("ON_TOUCH", "Upload max size: " + mUploadMaxSize.get());
final long duration = ((mUploadMaxSize.get() / 10 * 9) * 8) / (Constants.RECORDING_BIT_RATE_IN_MS / 1000); // 10% Overhead
CountDownTimer countDownTimer = new CountDownTimer(duration, 10) {
@Override
public void onTick(long millisecondsUntilFinished) {
limitTextView.setText(String.format(Locale.getDefault(), "%.2fs", (double) (millisecondsUntilFinished / 1000.0)));
long minutes = TimeUnit.MILLISECONDS.toMinutes(millisecondsUntilFinished);
long seconds = TimeUnit.MILLISECONDS.toSeconds(millisecondsUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisecondsUntilFinished));
limitTextView.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds));
}
@Override
@@ -416,19 +421,19 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
attachFromGalleryImageView.setVisibility(View.VISIBLE);
try {
mMediaRecorder.stop();
mMediaRecorder.stop(); // TODO: delete
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
};
// TODO: prevent the image view from moving outside the dialog box
attachRecordAudioImageView.setOnTouchListener((v, event) -> {
try {
attachRecordAudioImageView.performClick();
final int x = (int) event.getRawX();
int test = 0;
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
@@ -439,6 +444,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
limitTextView.setVisibility(View.VISIBLE);
attachDocumentImageView.setVisibility(View.INVISIBLE);
attachFromGalleryImageView.setVisibility(View.INVISIBLE);
abortRecordingImageView.setVisibility(View.VISIBLE);
mAudioFilePath = FileUtils.generateAudioRecordingFileName(this);
setupMediaRecorder(mAudioFilePath);
@@ -461,11 +467,34 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
mMediaRecorder.stop();
Rect recordButtonRect = ViewUtils.getRectFromView(attachRecordAudioImageView);
Rect abortButtonRect = ViewUtils.getRectFromView(abortRecordingImageView);
if(recordButtonRect.intersect(abortButtonRect)) {
if(!TextUtils.isEmpty(mAudioFilePath)) {
File audioFile = new File(mAudioFilePath);
if(audioFile.exists()) {
audioFile.delete();
}
}
dialog.dismiss();
return true;
}
if (!mChatPresenter.isAttached()) {
mChatPresenter.attachView(this);
}
//mCallback.sendFile(Uri.fromFile(new File(mAudioFilePath)), null);
Bundle bundle = new Bundle();
bundle.putString(Constants.FILENAME, mAudioFilePath);
Intent intent = new Intent(this, FileConfirmationActivity.class);
intent.putExtras(bundle);
intent.putExtra(Constants.EXTRA_GROUP, mGroup);
startActivityForResult(intent, 666);
dialog.dismiss();
return true;
@@ -475,9 +504,11 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
int newLeft = x - xDelta;
Log.d("ON_TOUCH", "dialog container left: " + mDialogContainer.left + "; x: " + x + "; limit to the right: " + mMaxMarginRight + "; old margin left: " + layoutParams2.leftMargin);
Log.d("ON_TOUCH", "new left margin: " + newLeft);
if(x > mDialogContainer.left && newLeft < mMaxMarginRight) {
int buttonLeft = ViewUtils.getRectFromView(attachRecordAudioImageView).left;
if(buttonLeft > mDialogContainer.left && newLeft < mMaxMarginRight) {
layoutParams2.leftMargin = newLeft;
layoutParams2.rightMargin = 0;
v.setLayoutParams(layoutParams2);
@@ -501,7 +532,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setAudioEncodingBitRate(32000);
mMediaRecorder.setAudioEncodingBitRate(Constants.RECORDING_BIT_RATE_IN_MS);
mMediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
mMediaRecorder.setOutputFile(audioFilePath);
}

View File

@@ -4,7 +4,6 @@ import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.api.common.ErrorHandlingResponseConverter;
import de.beyondsoft.ownchat.data.api.responses.MessageResponse;
import de.beyondsoft.ownchat.data.api.responses.MessagesResponse;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.data.events.GroupUpdatedEvent;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
@@ -27,15 +26,12 @@ import de.beyondsoft.ownchat.utils.rx.RxUtils;
import org.greenrobot.eventbus.EventBus;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.util.Pair;
import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -43,6 +39,7 @@ import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@@ -59,7 +56,6 @@ import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import static de.beyondsoft.ownchat.data.AppPrefsConstants.USER_ID;
@@ -165,51 +161,48 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
Subscription subscription = mChatService.getMessages(mGroupId, 0)
.compose(RxUtils.provideDefaultTransformer())
.flatMap(new ErrorHandlingResponseConverter<>())
.flatMap(new Func1<MessagesResponse, Observable<List<Message>>>() {
@Override
public Observable<List<Message>> call(MessagesResponse messageResponse) {
if (messageResponse.response.messages == null || messageResponse.response.messages.isEmpty()) {
return Observable.just(null);
}
Message lastMessage = messageResponse.response.messages.get(messageResponse.response.messages.size() - 1);
lastMessage.status = Message.Status.DELIVERED;
lastMessage.isRead = true;
if (!mMessages.contains(lastMessage)) {
long groupId = mGroupId;
resetMessages();
loadMessagesFromServerByGroupId(groupId);
return Observable.just(null);
}
for (int i = 0; i < mMessageToUpdate.size(); i++) {
Pair<Message, String> messageToUpdate = mMessageToUpdate.get(i);
if (isAttached()) {
getView().lastMessageUpdated(messageToUpdate.first, messageToUpdate.second);
}
}
mMessageToUpdate.clear();
ArrayList<Message> messages = new ArrayList<>();
for (int i = messageResponse.response.messages.size() - 1; i >= 0; i--) {
Message message = messageResponse.response.messages.get(i);
message.status = Message.Status.DELIVERED;
message.isRead = true;
message.userId = mUserIdPreference.get();
if (mMessages.contains(message)) {
continue;
}
messages.add(message);
}
return mMessageRealmRepository.updateMessages(messages, new MessageByIdSpecification(mUserIdPreference.get()));
.flatMap(messageResponse -> {
if (messageResponse.response.messages == null || messageResponse.response.messages.isEmpty()) {
return Observable.just(null);
}
Message lastMessage = messageResponse.response.messages.get(messageResponse.response.messages.size() - 1);
lastMessage.status = Message.Status.DELIVERED;
lastMessage.isRead = true;
if (!mMessages.contains(lastMessage)) {
long groupId1 = mGroupId;
resetMessages();
loadMessagesFromServerByGroupId(groupId1);
return Observable.just(null);
}
for (int i = 0; i < mMessageToUpdate.size(); i++) {
Pair<Message, String> messageToUpdate = mMessageToUpdate.get(i);
if (isAttached()) {
getView().lastMessageUpdated(messageToUpdate.first, messageToUpdate.second);
}
}
mMessageToUpdate.clear();
ArrayList<Message> messages = new ArrayList<>();
for (int i = messageResponse.response.messages.size() - 1; i >= 0; i--) {
Message message = messageResponse.response.messages.get(i);
message.status = Message.Status.DELIVERED;
message.isRead = true;
message.userId = mUserIdPreference.get();
if (mMessages.contains(message)) {
continue;
}
messages.add(message);
}
return mMessageRealmRepository.updateMessages(messages, new MessageByIdSpecification(mUserIdPreference.get()));
})
.subscribe(this::fetchNewMessagesSuccess, this::fetchNewMessagesError);
addSubscription(subscription);
@@ -418,7 +411,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
* Send the file to the server.
*/
@Override
public void sendFile(Uri fileUri, String messageText) {
public void sendFile(final Uri fileUri, String messageText) {
File file = getView().getFile(fileUri);
final String mimeType = FileUtils.getMimeType(file);
@@ -506,11 +499,11 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
storeMessageLocally(newMessage, message.id, false);
storeGroupLocally(mGroupId, message);
if (!isAttached()) {
if(!isAttached()) {
return;
}
if (mSystemUtils.isNetworkUnavailable()) {
if(mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
}
@@ -526,6 +519,15 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
baseResponse.response.message.isRead = true;
storeMessageLocally(baseResponse.response.message, message.id, false);
storeGroupLocally(mGroupId, baseResponse.response.message);
List<String> splitUriAsList = Arrays.asList(fileUri.toString().split("/"));
if(splitUriAsList.contains(Constants.AUDIO_RECORDINGS_DIR)) {
File f = getView().getFile(fileUri);
if(f != null && f.exists()) {
f.delete();
}
}
}
});
}

View File

@@ -36,4 +36,6 @@ public interface Constants {
String HAS_OPEN_CHAT = "has_open_chat";
String AUDIO_RECORDINGS_DIR = "audio_recordings";
int RECORDING_BIT_RATE_IN_MS = 32000;
}

View File

@@ -56,17 +56,6 @@ public abstract class ViewUtils {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
public static boolean isInViewInBounds(View view, int x, int y) {
Rect outRect = new Rect();
int[] location = new int[2];
view.getDrawingRect(outRect);
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
return outRect.contains(x, y);
}
public static Rect getRectFromView(View view) {
Rect outRect = new Rect();
int[] location = new int[2];
@@ -78,4 +67,16 @@ public abstract class ViewUtils {
return outRect;
}
public static Rect getHitRectFromView(View view) {
Rect outRect = new Rect();
int[] location = new int[2];
view.getHitRect(outRect);
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
return outRect;
}
}

View File

@@ -2,7 +2,7 @@
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/dialogGridLayout"
android:layout_width="200dp"
android:layout_width="203dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="false"
@@ -14,14 +14,28 @@
android:orientation="horizontal"
android:rowCount="1">
<ImageView
android:id="@+id/abortRecordingImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_margin="10dp"
android:layout_row="0"
android:adjustViewBounds="false"
android:contentDescription="@null"
android:cropToPadding="false"
android:src="@mipmap/ic_trash_bin"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/audioRecordingLimitTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_columnSpan="2"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_margin="20dp"
android:layout_column="1"
android:layout_gravity="center_vertical"
android:layout_margin="10dp"
android:layout_row="0"
android:textAlignment="center"
android:textColor="@color/colorBlack"

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B