Send voice messages

This commit is contained in:
Niels Andriesse 2021-06-28 11:11:29 +10:00
parent 0e23e45e89
commit 0da2487401
4 changed files with 63 additions and 22 deletions

View File

@ -102,7 +102,6 @@ import org.session.libsession.utilities.recipients.RecipientModifiedListener;
import org.session.libsession.utilities.ExpirationUtil; import org.session.libsession.utilities.ExpirationUtil;
import org.session.libsession.utilities.GroupUtil; import org.session.libsession.utilities.GroupUtil;
import org.session.libsession.utilities.MediaTypes; import org.session.libsession.utilities.MediaTypes;
import org.session.libsession.utilities.SSKEnvironment;
import org.session.libsession.utilities.ServiceUtil; import org.session.libsession.utilities.ServiceUtil;
import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.Util; import org.session.libsession.utilities.Util;
@ -165,8 +164,8 @@ import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
import org.thoughtcrime.securesms.loki.views.ProfilePictureView; import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity; import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
import org.thoughtcrime.securesms.mms.AttachmentManager; import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager;
import org.thoughtcrime.securesms.mms.AttachmentManager.MediaType; import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager.MediaType;
import org.thoughtcrime.securesms.mms.AudioSlide; import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.mms.GifSlide; import org.thoughtcrime.securesms.mms.GifSlide;
import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideApp;

View File

@ -8,8 +8,9 @@ import android.database.Cursor
import android.graphics.Rect import android.graphics.Rect
import android.graphics.Typeface import android.graphics.Typeface
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.*
import android.util.Log import android.util.Log
import android.util.Pair
import android.util.TypedValue import android.util.TypedValue
import android.view.* import android.view.*
import android.widget.RelativeLayout import android.widget.RelativeLayout
@ -39,10 +40,15 @@ import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.utilities.MediaTypes
import org.session.libsession.utilities.ServiceUtil
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.concurrent.AssertedSuccessListener
import org.session.libsignal.utilities.ListenableFuture import org.session.libsignal.utilities.ListenableFuture
import org.session.libsignal.utilities.guava.Optional
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.audio.AudioRecorder
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher
import org.thoughtcrime.securesms.conversation.v2.dialogs.* import org.thoughtcrime.securesms.conversation.v2.dialogs.*
import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton
@ -52,6 +58,7 @@ import org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCand
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallback import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallback
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.DraftDatabase import org.thoughtcrime.securesms.database.DraftDatabase
import org.thoughtcrime.securesms.database.DraftDatabase.Drafts import org.thoughtcrime.securesms.database.DraftDatabase.Drafts
@ -65,6 +72,7 @@ import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaSendActivity import org.thoughtcrime.securesms.mediasend.MediaSendActivity
import org.thoughtcrime.securesms.mms.* import org.thoughtcrime.securesms.mms.*
import org.thoughtcrime.securesms.notifications.MarkReadReceiver import org.thoughtcrime.securesms.notifications.MarkReadReceiver
import org.thoughtcrime.securesms.providers.BlobProvider
import org.thoughtcrime.securesms.util.DateUtils import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.MediaUtil import org.thoughtcrime.securesms.util.MediaUtil
import java.util.* import java.util.*
@ -83,6 +91,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private var unreadCount = 0 private var unreadCount = 0
// Attachments // Attachments
private val audioRecorder = AudioRecorder(this)
private val stopAudioHandler = Handler(Looper.getMainLooper())
private val stopVoiceMessageRecordingTask = Runnable { stopVoiceMessageRecording() }
private val attachmentManager by lazy { AttachmentManager(this, this) } private val attachmentManager by lazy { AttachmentManager(this, this) }
private var isLockViewExpanded = false private var isLockViewExpanded = false
private var isShowingAttachmentOptions = false private var isShowingAttachmentOptions = false
@ -621,6 +632,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
inputBarRecordingView.lock() inputBarRecordingView.lock()
} else { } else {
hideVoiceMessageUI() hideVoiceMessageUI()
stopVoiceMessageRecording()
} }
} }
@ -712,7 +724,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
} }
override fun onAttachmentChanged() { override fun onAttachmentChanged() {
// TODO: Do we need to do something here? // Do nothing
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
@ -777,6 +789,31 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private fun prepMediaForSending(uri: Uri, type: AttachmentManager.MediaType, width: Int?, height: Int?): ListenableFuture<Boolean> { private fun prepMediaForSending(uri: Uri, type: AttachmentManager.MediaType, width: Int?, height: Int?): ListenableFuture<Boolean> {
return attachmentManager.setMedia(glide, uri, type, MediaConstraints.getPushMediaConstraints(), width ?: 0, height ?: 0) return attachmentManager.setMedia(glide, uri, type, MediaConstraints.getPushMediaConstraints(), width ?: 0, height ?: 0)
} }
override fun startRecordingVoiceMessage() {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
audioRecorder.startRecording()
stopAudioHandler.postDelayed(stopVoiceMessageRecordingTask, 60000) // Limit voice messages to 1 minute each
}
fun stopVoiceMessageRecording() {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
val future = audioRecorder.stopRecording()
stopAudioHandler.removeCallbacks(stopVoiceMessageRecordingTask)
future.addListener(object : ListenableFuture.Listener<Pair<Uri?, Long?>> {
override fun onSuccess(result: Pair<Uri?, Long?>) {
val audioSlide = AudioSlide(this@ConversationActivityV2, result.first, result.second!!, MediaTypes.AUDIO_AAC, true)
val slideDeck = SlideDeck()
slideDeck.addSlide(audioSlide)
sendAttachments(slideDeck.asAttachments(), null)
}
override fun onFailure(e: ExecutionException) {
Toast.makeText(this@ConversationActivityV2, R.string.ConversationActivity_unable_to_record_audio, Toast.LENGTH_LONG).show()
}
})
}
// endregion // endregion
// region General // region General

View File

@ -52,7 +52,10 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
// Microphone button // Microphone button
microphoneOrSendButtonContainer.addView(microphoneButton) microphoneOrSendButtonContainer.addView(microphoneButton)
microphoneButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT) microphoneButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
microphoneButton.onLongPress = { showVoiceMessageUI() } microphoneButton.onLongPress = {
showVoiceMessageUI()
startRecordingVoiceMessage()
}
microphoneButton.onMove = { delegate?.onMicrophoneButtonMove(it) } microphoneButton.onMove = { delegate?.onMicrophoneButtonMove(it) }
microphoneButton.onCancel = { delegate?.onMicrophoneButtonCancel(it) } microphoneButton.onCancel = { delegate?.onMicrophoneButtonCancel(it) }
microphoneButton.onUp = { delegate?.onMicrophoneButtonUp(it) } microphoneButton.onUp = { delegate?.onMicrophoneButtonUp(it) }
@ -96,6 +99,10 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
delegate?.showVoiceMessageUI() delegate?.showVoiceMessageUI()
} }
private fun startRecordingVoiceMessage() {
delegate?.startRecordingVoiceMessage()
}
// Drafting quotes and drafting link previews is mutually exclusive, i.e. you can't draft // Drafting quotes and drafting link previews is mutually exclusive, i.e. you can't draft
// a quote and a link preview at the same time. // a quote and a link preview at the same time.
@ -159,6 +166,7 @@ interface InputBarDelegate {
fun inputBarEditTextContentChanged(newContent: CharSequence) fun inputBarEditTextContentChanged(newContent: CharSequence)
fun toggleAttachmentOptions() fun toggleAttachmentOptions()
fun showVoiceMessageUI() fun showVoiceMessageUI()
fun startRecordingVoiceMessage()
fun onMicrophoneButtonMove(event: MotionEvent) fun onMicrophoneButtonMove(event: MotionEvent)
fun onMicrophoneButtonCancel(event: MotionEvent) fun onMicrophoneButtonCancel(event: MotionEvent)
fun onMicrophoneButtonUp(event: MotionEvent) fun onMicrophoneButtonUp(event: MotionEvent)

View File

@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.thoughtcrime.securesms.mms; package org.thoughtcrime.securesms.conversation.v2.utilities;
import android.Manifest; import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@ -23,29 +23,31 @@ import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.PorterDuff;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.provider.ContactsContract;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.MediaPreviewActivity;
import org.thoughtcrime.securesms.loki.views.MessageAudioView;
import org.thoughtcrime.securesms.components.DocumentView;
import org.thoughtcrime.securesms.components.RemovableEditableMediaView;
import org.thoughtcrime.securesms.conversation.v2.utilities.ThumbnailView;
import org.session.libsignal.utilities.NoExternalStorageException; import org.session.libsignal.utilities.NoExternalStorageException;
import org.thoughtcrime.securesms.giph.ui.GiphyActivity; import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
import org.session.libsignal.utilities.Log; import org.session.libsignal.utilities.Log;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity; import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.mms.DocumentSlide;
import org.thoughtcrime.securesms.mms.GifSlide;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.ImageSlide;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.mms.VideoSlide;
import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.providers.BlobProvider;
import org.session.libsignal.utilities.ExternalStorageUtil; import org.session.libsignal.utilities.ExternalStorageUtil;
@ -53,13 +55,8 @@ import org.thoughtcrime.securesms.util.FileProviderUtil;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import org.session.libsignal.utilities.guava.Optional; import org.session.libsignal.utilities.guava.Optional;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.utilities.recipients.Recipient; import org.session.libsession.utilities.recipients.Recipient;
import org.session.libsession.utilities.ThemeUtil;
import org.session.libsession.utilities.ViewUtil;
import org.session.libsession.utilities.Stub;
import org.session.libsignal.utilities.ListenableFuture; import org.session.libsignal.utilities.ListenableFuture;
import org.session.libsignal.utilities.ListenableFuture.Listener;
import org.session.libsignal.utilities.SettableFuture; import org.session.libsignal.utilities.SettableFuture;
import java.io.File; import java.io.File;
@ -67,7 +64,6 @@ import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
import network.loki.messenger.R; import network.loki.messenger.R;
@ -244,7 +240,8 @@ public class AttachmentManager {
return result; return result;
} }
public @NonNull SlideDeck buildSlideDeck() { public @NonNull
SlideDeck buildSlideDeck() {
SlideDeck deck = new SlideDeck(); SlideDeck deck = new SlideDeck();
if (slide.isPresent()) deck.addSlide(slide.get()); if (slide.isPresent()) deck.addSlide(slide.get());
return deck; return deck;