Merge branch 'master' into master-android

This commit is contained in:
Evgeny Poberezkin
2024-04-22 22:24:30 +01:00
14 changed files with 93 additions and 36 deletions
@@ -67,10 +67,13 @@ actual fun getKeyboardState(): State<KeyboardState> {
return keyboardState
}
actual fun hideKeyboard(view: Any?) {
actual fun hideKeyboard(view: Any?, clearFocus: Boolean) {
// LALAL
// LocalSoftwareKeyboardController.current?.hide()
if (view is View) {
if (clearFocus) {
view.clearFocus()
}
(androidAppContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(view.windowToken, 0)
}
}
@@ -64,6 +64,7 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
}
override fun start() {
am.mode = AudioManager.MODE_IN_COMMUNICATION
am.registerAudioDeviceCallback(audioCallback, null)
am.addOnCommunicationDeviceChangedListener(Executors.newSingleThreadExecutor(), listener)
}
@@ -75,7 +76,6 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
override fun selectLastExternalDeviceOrDefault(speaker: Boolean, keepAnyNonEarpiece: Boolean) {
Log.d(TAG, "selectLastExternalDeviceOrDefault: set audio mode, speaker enabled: $speaker")
am.mode = AudioManager.MODE_IN_COMMUNICATION
val commDevice = am.communicationDevice
if (keepAnyNonEarpiece && commDevice != null && commDevice.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) {
// some external device or speaker selected already, no need to change it
@@ -98,7 +98,6 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
}
override fun selectDevice(id: Int) {
am.mode = AudioManager.MODE_IN_COMMUNICATION
val device = devices.value.lastOrNull { it.id == id }
if (device != null && am.communicationDevice?.id != id ) {
am.setCommunicationDevice(device)
@@ -115,40 +114,32 @@ class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Added audio devices: ${addedDevices.map { it.type }}")
super.onAudioDevicesAdded(addedDevices)
val wasSize = devices.value.size
devices.value += addedDevices.filter { it.hasSupportedType() }
val addedCount = devices.value.size - wasSize
//if (addedCount > 0 && chatModel.activeCall.value?.callState == CallState.Connected) {
// Setting params in Connected state makes sure that Bluetooth will NOT be broken on Android < 12
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, false)
//}
devices.value = am.getDevices(AudioManager.GET_DEVICES_OUTPUTS).filter { it.hasSupportedType() }.excludeSameType().excludeEarpieceIfWired()
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, false)
}
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Removed audio devices: ${removedDevices.map { it.type }}")
super.onAudioDevicesRemoved(removedDevices)
val wasSize = devices.value.size
devices.value = devices.value.filterNot { removedDevices.any { rm -> rm.id == it.id } }
//val removedCount = wasSize - devices.value.size
//if (devices.value.count { it.hasSupportedType() } == 2 && chatModel.activeCall.value?.callState == CallState.Connected) {
// Setting params in Connected state makes sure that Bluetooth will NOT be broken on Android < 12
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, true)
//}
devices.value = am.getDevices(AudioManager.GET_DEVICES_OUTPUTS).filter { it.hasSupportedType() }.excludeSameType().excludeEarpieceIfWired()
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, true)
}
}
override fun start() {
am.mode = AudioManager.MODE_IN_COMMUNICATION
am.registerAudioDeviceCallback(audioCallback, null)
}
override fun stop() {
am.unregisterAudioDeviceCallback(audioCallback)
am.stopBluetoothSco()
}
override fun selectLastExternalDeviceOrDefault(speaker: Boolean, keepAnyNonEarpiece: Boolean) {
Log.d(TAG, "selectLastExternalDeviceOrDefault: set audio mode, speaker enabled: $speaker")
val preferredSecondaryDevice = if (speaker) AudioDeviceInfo.TYPE_BUILTIN_SPEAKER else AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
val externalDevice = devices.value.lastOrNull { it.hasSupportedType() && it.isSource && it.isSink && it.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && it.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE }
val externalDevice = devices.value.lastOrNull { it.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && it.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE }
if (externalDevice != null) {
selectDevice(externalDevice.id)
} else {
@@ -166,7 +157,7 @@ class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
val isExternalDevice = device != null && device.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && device.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
if (isExternalDevice) {
am.isSpeakerphoneOn = false
if (device?.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES) {
if (device?.type == AudioDeviceInfo.TYPE_WIRED_HEADSET || device?.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES) {
am.isWiredHeadsetOn = true
am.stopBluetoothSco()
am.isBluetoothScoOn = false
@@ -194,11 +185,18 @@ class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> true
AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> true
AudioDeviceInfo.TYPE_BLE_HEADSET -> true
AudioDeviceInfo.TYPE_BLE_SPEAKER -> true
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> true
else -> false
}
private fun List<AudioDeviceInfo>.excludeSameType(): List<AudioDeviceInfo> =
groupBy { it.type }.flatMap { devices -> listOf(devices.value.minByOrNull { it.id }!!) }
// Earpiece will not work if there is a wired connection
private fun List<AudioDeviceInfo>.excludeEarpieceIfWired(): List<AudioDeviceInfo> =
if (any { it.type == AudioDeviceInfo.TYPE_WIRED_HEADSET || it.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES })
filter { it.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE }
else this
}
val AudioDeviceInfo.icon: ImageResource
@@ -225,11 +223,15 @@ val AudioDeviceInfo.name: StringResource?
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
AudioDeviceInfo.TYPE_BLE_HEADSET,
AudioDeviceInfo.TYPE_BLE_SPEAKER -> null // Use product name instead
AudioDeviceInfo.TYPE_BLE_SPEAKER -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Use product name instead
null
} else {
MR.strings.audio_device_bluetooth
}
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> MR.strings.audio_device_wired_headphones
AudioDeviceInfo.TYPE_USB_HEADSET, AudioDeviceInfo.TYPE_USB_DEVICE -> null // Use product name instead
else -> null // Use product name instead
}
@@ -87,7 +87,9 @@ actual fun ActiveCallView() {
}
val callAudioDeviceManager = remember { CallAudioDeviceManagerInterface.new() }
DisposableEffect(Unit) {
callAudioDeviceManager.start()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
callAudioDeviceManager.start()
}
onDispose {
CallSoundsPlayer.stop()
if (wasConnected.value) {
@@ -120,13 +122,24 @@ actual fun ActiveCallView() {
val callType = CallType(call.localMedia, r.capabilities)
chatModel.controller.apiSendCallInvitation(callRh, call.contact, callType)
updateActiveCall(call) { it.copy(callState = CallState.InvitationSent, localCapabilities = r.capabilities) }
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
// Starting is delayed to make Android <= 11 working good with Bluetooth
callAudioDeviceManager.start()
} else {
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
}
CallSoundsPlayer.startConnectingCallSound(scope)
activeCallWaitDeliveryReceipt(scope)
}
is WCallResponse.Offer -> withBGApi {
chatModel.controller.apiSendCallOffer(callRh, call.contact, r.offer, r.iceCandidates, call.localMedia, r.capabilities)
updateActiveCall(call) { it.copy(callState = CallState.OfferSent, localCapabilities = r.capabilities) }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
// Starting is delayed to make Android <= 11 working good with Bluetooth
callAudioDeviceManager.start()
} else {
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
}
}
is WCallResponse.Answer -> withBGApi {
chatModel.controller.apiSendCallAnswer(callRh, call.contact, r.answer, r.iceCandidates)
@@ -141,7 +154,6 @@ actual fun ActiveCallView() {
val callStatus = json.decodeFromString<WebRTCCallStatus>("\"${r.state.connectionState}\"")
if (callStatus == WebRTCCallStatus.Connected) {
updateActiveCall(call) { it.copy(callState = CallState.Connected, connectedAt = Clock.System.now()) }
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
}
withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) }
} catch (e: Throwable) {
@@ -149,9 +161,6 @@ actual fun ActiveCallView() {
}
is WCallResponse.Connected -> {
updateActiveCall(call) { it.copy(callState = CallState.Connected, connectionInfo = r.connectionInfo) }
scope.launch {
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
}
}
is WCallResponse.End -> {
withBGApi { chatModel.callManager.endCall(call) }
@@ -13,7 +13,7 @@ expect fun LocalMultiplatformView(): Any?
@Composable
expect fun getKeyboardState(): State<KeyboardState>
expect fun hideKeyboard(view: Any?)
expect fun hideKeyboard(view: Any?, clearFocus: Boolean = false)
expect fun androidIsFinishingMainActivity(): Boolean
@@ -135,7 +135,9 @@ fun PasscodeView(
if (!buttonsEnabled.value) {
ProgressIndicator()
}
val view = LocalMultiplatformView()
LaunchedEffect(Unit) {
hideKeyboard(view, true)
focusRequester.requestFocus()
// Disallow to steal a focus by clicking on buttons or using Tab
focusRequester.captureFocus()
@@ -521,6 +521,37 @@ private val versionDescriptions: List<VersionDescription> = listOf(
)
)
),
VersionDescription(
version = "v5.7",
features = listOf(
FeatureDescription(
icon = MR.images.ic_vpn_key_filled,
titleId = MR.strings.v5_6_quantum_resistant_encryption,
descrId = MR.strings.v5_7_quantum_resistant_encryption_descr
),
FeatureDescription(
icon = MR.images.ic_forward,
titleId = MR.strings.v5_7_forward,
descrId = MR.strings.v5_7_forward_descr
),
FeatureDescription(
icon = MR.images.ic_music_note,
titleId = MR.strings.v5_7_call_sounds,
descrId = MR.strings.v5_7_call_sounds_descr
),
FeatureDescription(
icon = MR.images.ic_wifi_tethering,
titleId = MR.strings.v5_7_network,
descrId = MR.strings.v5_7_network_descr
),
FeatureDescription(
icon = MR.images.ic_translate,
titleId = MR.strings.v5_7_new_interface_languages,
descrId = MR.strings.whats_new_thanks_to_users_contribute_weblate,
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
)
)
),
)
private val lastVersion = versionDescriptions.last().version
@@ -212,7 +212,7 @@ object AppearanceScope {
"it" to "Italiano",
"iw" to "עִברִית",
"ja" to "日本語",
"lt" to "Lietuvių kalba",
"lt" to "Lietuvių",
"nl" to "Nederlands",
"pl" to "Polski",
"pt-BR" to "Português, Brasil",
@@ -839,6 +839,7 @@
<string name="audio_device_earpiece">Earpiece</string>
<string name="audio_device_speaker">Speaker</string>
<string name="audio_device_wired_headphones">Headphones</string>
<string name="audio_device_bluetooth">Bluetooth</string>
<!-- SimpleXInfo -->
<string name="next_generation_of_private_messaging">The next generation of private messaging</string>
@@ -1764,6 +1765,14 @@
<string name="v5_6_picture_in_picture_calls_descr">Use the app while in the call.</string>
<string name="v5_6_safer_groups">Safer groups</string>
<string name="v5_6_safer_groups_descr">Admins can block a member for all.</string>
<string name="v5_7_quantum_resistant_encryption_descr">Will be enabled in direct chats!</string>
<string name="v5_7_forward">Forward and save messages</string>
<string name="v5_7_forward_descr">Message source remains private.</string>
<string name="v5_7_call_sounds">In-call sounds</string>
<string name="v5_7_call_sounds_descr">When connecting audio and video calls.</string>
<string name="v5_7_network">Network management</string>
<string name="v5_7_network_descr">More reliable network connection.</string>
<string name="v5_7_new_interface_languages">Lithuanian UI</string>
<!-- CustomTimePicker -->
<string name="custom_time_unit_seconds">seconds</string>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M393.814-125q-62.314 0-104.564-42.381Q247-209.762 247-272q0-62.237 42.25-104.619Q331.5-419 394-419q27.5 0 50.25 8t39.25 22.5v-418q0-11.925 8-20.213Q499.5-835 512-835h172.5q12.5 0 20.75 8.24 8.25 8.239 8.25 20.093V-733q0 12.5-8.25 20.75T684.5-704H541v432q0 62.238-42.436 104.619T393.814-125Z"/></svg>

After

Width:  |  Height:  |  Size: 396 B

@@ -16,7 +16,7 @@ actual fun LocalMultiplatformView(): Any? = null
@Composable
actual fun getKeyboardState(): State<KeyboardState> = remember { mutableStateOf(KeyboardState.Opened) }
actual fun hideKeyboard(view: Any?) {}
actual fun hideKeyboard(view: Any?, clearFocus: Boolean) {}
actual fun androidIsFinishingMainActivity(): Boolean = false
+1 -1
View File
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: fe28e02be779fb0357a7f650bd327a75f4aaab95
tag: daa866f3331cf882f1030ae636f9e27a2498ca8b
source-repository-package
type: git
+1 -1
View File
@@ -1,5 +1,5 @@
name: simplex-chat
version: 5.7.0.2
version: 5.7.0.3
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
+1 -1
View File
@@ -1,5 +1,5 @@
{
"https://github.com/simplex-chat/simplexmq.git"."fe28e02be779fb0357a7f650bd327a75f4aaab95" = "1hwh0kx6ljskjx7svxpwmga79dfa2vz9qq0mwbqr6kkb9kf6qdd3";
"https://github.com/simplex-chat/simplexmq.git"."daa866f3331cf882f1030ae636f9e27a2498ca8b" = "1bfzw8q8jgblpqh0vjvhs3ddyvgxrdpv18gy84yr6kmvssmdgs76";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
+1 -1
View File
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
version: 5.7.0.2
version: 5.7.0.3
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat