Работающие звонки
This commit is contained in:
@@ -6,7 +6,6 @@ import android.util.Log
|
||||
import com.rosetta.messenger.data.MessageRepository
|
||||
import java.security.MessageDigest
|
||||
import java.security.SecureRandom
|
||||
import java.util.IdentityHashMap
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -137,8 +136,8 @@ object CallManager {
|
||||
|
||||
// E2EE (XChaCha20 — compatible with Desktop)
|
||||
private var sharedKeyBytes: ByteArray? = null
|
||||
private val senderEncryptors = IdentityHashMap<RtpSender, XChaCha20E2EE.Encryptor>()
|
||||
private val receiverDecryptors = IdentityHashMap<RtpReceiver, XChaCha20E2EE.Decryptor>()
|
||||
private val senderEncryptors = LinkedHashMap<String, XChaCha20E2EE.Encryptor>()
|
||||
private val receiverDecryptors = LinkedHashMap<String, XChaCha20E2EE.Decryptor>()
|
||||
private var pendingAudioSenderForE2ee: RtpSender? = null
|
||||
private var lastRemoteOfferFingerprint: String = ""
|
||||
private var lastLocalOfferFingerprint: String = ""
|
||||
@@ -1063,11 +1062,22 @@ object CallManager {
|
||||
breadcrumb("STATE[$marker] ${buildStateSnapshot()}")
|
||||
}
|
||||
|
||||
private fun senderMapKey(sender: RtpSender): String {
|
||||
val id = runCatching { sender.id() }.getOrNull().orEmpty()
|
||||
return if (id.isNotBlank()) "sid:$id" else "sender@${System.identityHashCode(sender)}"
|
||||
}
|
||||
|
||||
private fun receiverMapKey(receiver: RtpReceiver): String {
|
||||
val id = runCatching { receiver.id() }.getOrNull().orEmpty()
|
||||
return if (id.isNotBlank()) "rid:$id" else "recv@${System.identityHashCode(receiver)}"
|
||||
}
|
||||
|
||||
private fun attachSenderE2EE(sender: RtpSender?) {
|
||||
if (!e2eeAvailable) return
|
||||
val key = sharedKeyBytes ?: return
|
||||
if (sender == null) return
|
||||
val existing = senderEncryptors[sender]
|
||||
val mapKey = senderMapKey(sender)
|
||||
val existing = senderEncryptors[mapKey]
|
||||
if (existing != null) {
|
||||
runCatching { sender.setFrameEncryptor(existing) }
|
||||
return
|
||||
@@ -1086,7 +1096,7 @@ object CallManager {
|
||||
breadcrumb("4. calling sender.setFrameEncryptor…")
|
||||
sender.setFrameEncryptor(enc)
|
||||
breadcrumb("5. setFrameEncryptor OK!")
|
||||
senderEncryptors[sender] = enc
|
||||
senderEncryptors[mapKey] = enc
|
||||
pendingAudioSenderForE2ee = null
|
||||
} catch (e: Throwable) {
|
||||
saveCrashReport("attachSenderE2EE failed", e)
|
||||
@@ -1104,7 +1114,8 @@ object CallManager {
|
||||
if (!e2eeAvailable) return
|
||||
val key = sharedKeyBytes ?: return
|
||||
if (receiver == null) return
|
||||
val existing = receiverDecryptors[receiver]
|
||||
val mapKey = receiverMapKey(receiver)
|
||||
val existing = receiverDecryptors[mapKey]
|
||||
if (existing != null) {
|
||||
runCatching { receiver.setFrameDecryptor(existing) }
|
||||
return
|
||||
@@ -1123,7 +1134,7 @@ object CallManager {
|
||||
breadcrumb("9. calling receiver.setFrameDecryptor…")
|
||||
receiver.setFrameDecryptor(dec)
|
||||
breadcrumb("10. setFrameDecryptor OK!")
|
||||
receiverDecryptors[receiver] = dec
|
||||
receiverDecryptors[mapKey] = dec
|
||||
} catch (e: Throwable) {
|
||||
saveCrashReport("attachReceiverE2EE failed", e)
|
||||
Log.e(TAG, "E2EE: receiver decryptor failed", e)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.rosetta.messenger.ui.crashlogs
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -8,13 +9,16 @@ import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.BugReport
|
||||
import androidx.compose.material.icons.filled.ContentCopy
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Share
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -263,6 +267,8 @@ private fun CrashDetailScreen(
|
||||
onDelete: () -> Unit
|
||||
) {
|
||||
var showDeleteDialog by remember { mutableStateOf(false) }
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
val context = LocalContext.current
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@@ -274,6 +280,14 @@ private fun CrashDetailScreen(
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = {
|
||||
clipboardManager.setText(AnnotatedString(crashReport.content))
|
||||
Toast.makeText(context, "Full log copied", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
) {
|
||||
Icon(Icons.Default.ContentCopy, contentDescription = "Copy Full Log")
|
||||
}
|
||||
IconButton(onClick = { /* TODO: Share */ }) {
|
||||
Icon(Icons.Default.Share, contentDescription = "Share")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user