Merge pull request #7393 from vector-im/feature/fre/voice_broadcast_labs_flag
Add voice broadcast labs setting
This commit is contained in:
commit
1b9c2ed77c
1
changelog.d/7393.wip
Normal file
1
changelog.d/7393.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Voice Broadcast] Enable the feature (behind a lab flag and only for Android 10 and up)
|
@ -3346,6 +3346,8 @@
|
|||||||
<string name="labs_enable_session_manager_summary">Have greater visibility and control over all your sessions.</string>
|
<string name="labs_enable_session_manager_summary">Have greater visibility and control over all your sessions.</string>
|
||||||
<string name="labs_enable_client_info_recording_title">Enable client info recording</string>
|
<string name="labs_enable_client_info_recording_title">Enable client info recording</string>
|
||||||
<string name="labs_enable_client_info_recording_summary">Record the client name, version, and url to recognise sessions more easily in session manager.</string>
|
<string name="labs_enable_client_info_recording_summary">Record the client name, version, and url to recognise sessions more easily in session manager.</string>
|
||||||
|
<string name="labs_enable_voice_broadcast_title">Enable voice broadcast (under active development)</string>
|
||||||
|
<string name="labs_enable_voice_broadcast_summary">Be able to record and send voice broadcast in room timeline.</string>
|
||||||
|
|
||||||
<!-- Note to translators: %s will be replaces with selected space name -->
|
<!-- Note to translators: %s will be replaces with selected space name -->
|
||||||
<string name="home_empty_space_no_rooms_title">%s\nis looking a little empty.</string>
|
<string name="home_empty_space_no_rooms_title">%s\nis looking a little empty.</string>
|
||||||
|
@ -49,6 +49,8 @@
|
|||||||
<bool name="settings_timeline_show_live_sender_info_default">false</bool>
|
<bool name="settings_timeline_show_live_sender_info_default">false</bool>
|
||||||
<bool name="settings_labs_rich_text_editor_visible">true</bool>
|
<bool name="settings_labs_rich_text_editor_visible">true</bool>
|
||||||
<bool name="settings_labs_rich_text_editor_default">false</bool>
|
<bool name="settings_labs_rich_text_editor_default">false</bool>
|
||||||
|
<bool name="settings_labs_enable_voice_broadcast_visible">true</bool>
|
||||||
|
<bool name="settings_labs_enable_voice_broadcast_default">false</bool>
|
||||||
<!-- Level 1: Advanced settings -->
|
<!-- Level 1: Advanced settings -->
|
||||||
|
|
||||||
<!-- Level 1: Help and about -->
|
<!-- Level 1: Help and about -->
|
||||||
|
@ -62,5 +62,5 @@ class DefaultVectorFeatures : VectorFeatures {
|
|||||||
override fun isQrCodeLoginEnabled(): Boolean = true
|
override fun isQrCodeLoginEnabled(): Boolean = true
|
||||||
override fun isQrCodeLoginForAllServers(): Boolean = false
|
override fun isQrCodeLoginForAllServers(): Boolean = false
|
||||||
override fun isReciprocateQrCodeLogin(): Boolean = false
|
override fun isReciprocateQrCodeLogin(): Boolean = false
|
||||||
override fun isVoiceBroadcastEnabled(): Boolean = false
|
override fun isVoiceBroadcastEnabled(): Boolean = true
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
|||||||
)
|
)
|
||||||
attachmentTypeSelector.setAttachmentVisibility(
|
attachmentTypeSelector.setAttachmentVisibility(
|
||||||
AttachmentTypeSelectorView.Type.VOICE_BROADCAST,
|
AttachmentTypeSelectorView.Type.VOICE_BROADCAST,
|
||||||
vectorFeatures.isVoiceBroadcastEnabled(), // TODO check user permission
|
vectorPreferences.isVoiceBroadcastEnabled(), // TODO check user permission
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
attachmentTypeSelector.show(composer.attachmentButton)
|
attachmentTypeSelector.show(composer.attachmentButton)
|
||||||
|
@ -74,6 +74,7 @@ class VectorPreferences @Inject constructor(
|
|||||||
const val SETTINGS_LABS_RICH_TEXT_EDITOR_KEY = "SETTINGS_LABS_RICH_TEXT_EDITOR_KEY"
|
const val SETTINGS_LABS_RICH_TEXT_EDITOR_KEY = "SETTINGS_LABS_RICH_TEXT_EDITOR_KEY"
|
||||||
const val SETTINGS_LABS_NEW_SESSION_MANAGER_KEY = "SETTINGS_LABS_NEW_SESSION_MANAGER_KEY"
|
const val SETTINGS_LABS_NEW_SESSION_MANAGER_KEY = "SETTINGS_LABS_NEW_SESSION_MANAGER_KEY"
|
||||||
const val SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY = "SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY"
|
const val SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY = "SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY"
|
||||||
|
const val SETTINGS_LABS_VOICE_BROADCAST_KEY = "SETTINGS_LABS_VOICE_BROADCAST_KEY"
|
||||||
const val SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY"
|
const val SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY"
|
||||||
const val SETTINGS_CRYPTOGRAPHY_DIVIDER_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_DIVIDER_PREFERENCE_KEY"
|
const val SETTINGS_CRYPTOGRAPHY_DIVIDER_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_DIVIDER_PREFERENCE_KEY"
|
||||||
const val SETTINGS_CRYPTOGRAPHY_MANAGE_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_MANAGE_PREFERENCE_KEY"
|
const val SETTINGS_CRYPTOGRAPHY_MANAGE_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_MANAGE_PREFERENCE_KEY"
|
||||||
@ -1203,4 +1204,9 @@ class VectorPreferences @Inject constructor(
|
|||||||
fun isRichTextEditorEnabled(): Boolean {
|
fun isRichTextEditorEnabled(): Boolean {
|
||||||
return defaultPrefs.getBoolean(SETTINGS_LABS_RICH_TEXT_EDITOR_KEY, getDefault(R.bool.settings_labs_rich_text_editor_default))
|
return defaultPrefs.getBoolean(SETTINGS_LABS_RICH_TEXT_EDITOR_KEY, getDefault(R.bool.settings_labs_rich_text_editor_default))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isVoiceBroadcastEnabled(): Boolean {
|
||||||
|
return vectorFeatures.isVoiceBroadcastEnabled() &&
|
||||||
|
defaultPrefs.getBoolean(SETTINGS_LABS_VOICE_BROADCAST_KEY, getDefault(R.bool.settings_labs_enable_voice_broadcast_default))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.app.features.settings.labs
|
package im.vector.app.features.settings.labs
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.method.LinkMovementMethod
|
import android.text.method.LinkMovementMethod
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
@ -90,6 +91,11 @@ class VectorSettingsLabsFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_LABS_VOICE_BROADCAST_KEY)?.let { pref ->
|
||||||
|
// Voice Broadcast recording is not available on Android < 10
|
||||||
|
pref.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && vectorFeatures.isVoiceBroadcastEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
configureUnreadNotificationsAsTabPreference()
|
configureUnreadNotificationsAsTabPreference()
|
||||||
configureEnableClientInfoRecordingPreference()
|
configureEnableClientInfoRecordingPreference()
|
||||||
}
|
}
|
||||||
|
@ -22,5 +22,5 @@ object VoiceBroadcastConstants {
|
|||||||
const val STATE_ROOM_VOICE_BROADCAST_INFO = "io.element.voice_broadcast_info"
|
const val STATE_ROOM_VOICE_BROADCAST_INFO = "io.element.voice_broadcast_info"
|
||||||
|
|
||||||
/** Default voice broadcast chunk duration, in seconds. */
|
/** Default voice broadcast chunk duration, in seconds. */
|
||||||
const val DEFAULT_CHUNK_LENGTH_IN_SECONDS = 30
|
const val DEFAULT_CHUNK_LENGTH_IN_SECONDS = 120
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.app.features.voicebroadcast
|
package im.vector.app.features.voicebroadcast
|
||||||
|
|
||||||
|
import androidx.annotation.IntRange
|
||||||
import im.vector.app.features.voice.VoiceRecorder
|
import im.vector.app.features.voice.VoiceRecorder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@ -26,6 +27,6 @@ interface VoiceBroadcastRecorder : VoiceRecorder {
|
|||||||
fun startRecord(roomId: String, chunkLength: Int)
|
fun startRecord(roomId: String, chunkLength: Int)
|
||||||
|
|
||||||
fun interface Listener {
|
fun interface Listener {
|
||||||
fun onVoiceMessageCreated(file: File)
|
fun onVoiceMessageCreated(file: File, @IntRange(from = 1) sequence: Int)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ class VoiceBroadcastRecorderQ(
|
|||||||
) : AbstractVoiceRecorderQ(context), VoiceBroadcastRecorder {
|
) : AbstractVoiceRecorderQ(context), VoiceBroadcastRecorder {
|
||||||
|
|
||||||
private var maxFileSize = 0L // zero or negative for no limit
|
private var maxFileSize = 0L // zero or negative for no limit
|
||||||
|
private var currentSequence = 0
|
||||||
|
|
||||||
override var listener: VoiceBroadcastRecorder.Listener? = null
|
override var listener: VoiceBroadcastRecorder.Listener? = null
|
||||||
|
|
||||||
@ -51,6 +52,7 @@ class VoiceBroadcastRecorderQ(
|
|||||||
|
|
||||||
override fun startRecord(roomId: String, chunkLength: Int) {
|
override fun startRecord(roomId: String, chunkLength: Int) {
|
||||||
maxFileSize = (chunkLength * audioEncodingBitRate / 8).toLong()
|
maxFileSize = (chunkLength * audioEncodingBitRate / 8).toLong()
|
||||||
|
currentSequence = 1
|
||||||
startRecord(roomId)
|
startRecord(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +60,7 @@ class VoiceBroadcastRecorderQ(
|
|||||||
super.stopRecord()
|
super.stopRecord()
|
||||||
notifyOutputFileCreated()
|
notifyOutputFileCreated()
|
||||||
listener = null
|
listener = null
|
||||||
|
currentSequence = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun release() {
|
override fun release() {
|
||||||
@ -71,11 +74,12 @@ class VoiceBroadcastRecorderQ(
|
|||||||
|
|
||||||
private fun onNextOutputFileStarted() {
|
private fun onNextOutputFileStarted() {
|
||||||
notifyOutputFileCreated()
|
notifyOutputFileCreated()
|
||||||
|
currentSequence++
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyOutputFileCreated() {
|
private fun notifyOutputFileCreated() {
|
||||||
outputFile?.let {
|
outputFile?.let {
|
||||||
listener?.onVoiceMessageCreated(it)
|
listener?.onVoiceMessageCreated(it, currentSequence)
|
||||||
outputFile = nextOutputFile
|
outputFile = nextOutputFile
|
||||||
nextOutputFile = null
|
nextOutputFile = null
|
||||||
}
|
}
|
||||||
|
@ -79,20 +79,21 @@ class StartVoiceBroadcastUseCase @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startRecording(room: Room, eventId: String, chunkLength: Int) {
|
private fun startRecording(room: Room, eventId: String, chunkLength: Int) {
|
||||||
voiceBroadcastRecorder?.listener = VoiceBroadcastRecorder.Listener { file ->
|
voiceBroadcastRecorder?.listener = VoiceBroadcastRecorder.Listener { file, sequence ->
|
||||||
sendVoiceFile(room, file, eventId)
|
sendVoiceFile(room, file, eventId, sequence)
|
||||||
}
|
}
|
||||||
voiceBroadcastRecorder?.startRecord(room.roomId, chunkLength)
|
voiceBroadcastRecorder?.startRecord(room.roomId, chunkLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendVoiceFile(room: Room, voiceMessageFile: File, referenceEventId: String) {
|
private fun sendVoiceFile(room: Room, voiceMessageFile: File, referenceEventId: String, sequence: Int) {
|
||||||
val outputFileUri = FileProvider.getUriForFile(
|
val outputFileUri = FileProvider.getUriForFile(
|
||||||
context,
|
context,
|
||||||
buildMeta.applicationId + ".fileProvider",
|
buildMeta.applicationId + ".fileProvider",
|
||||||
voiceMessageFile,
|
voiceMessageFile,
|
||||||
"Voice message.${voiceMessageFile.extension}"
|
"Voice Broadcast Part ($sequence).${voiceMessageFile.extension}"
|
||||||
)
|
)
|
||||||
val audioType = outputFileUri.toMultiPickerAudioType(context) ?: return
|
val audioType = outputFileUri.toMultiPickerAudioType(context) ?: return
|
||||||
|
// TODO put sequence in event content
|
||||||
room.sendService().sendMedia(
|
room.sendService().sendMedia(
|
||||||
attachment = audioType.toContentAttachmentData(isVoiceMessage = true),
|
attachment = audioType.toContentAttachmentData(isVoiceMessage = true),
|
||||||
compressBeforeSending = false,
|
compressBeforeSending = false,
|
||||||
|
@ -117,4 +117,11 @@
|
|||||||
android:title="@string/labs_enable_client_info_recording_title"
|
android:title="@string/labs_enable_client_info_recording_title"
|
||||||
app:isPreferenceVisible="@bool/settings_labs_client_info_recording_visible" />
|
app:isPreferenceVisible="@bool/settings_labs_client_info_recording_visible" />
|
||||||
|
|
||||||
|
<im.vector.app.core.preference.VectorSwitchPreference
|
||||||
|
android:defaultValue="@bool/settings_labs_enable_voice_broadcast_default"
|
||||||
|
android:key="SETTINGS_LABS_VOICE_BROADCAST_KEY"
|
||||||
|
android:summary="@string/labs_enable_voice_broadcast_summary"
|
||||||
|
android:title="@string/labs_enable_voice_broadcast_title"
|
||||||
|
app:isPreferenceVisible="@bool/settings_labs_enable_voice_broadcast_visible" />
|
||||||
|
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
||||||
|
Loading…
Reference in New Issue
Block a user