diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/TelecomCallManager.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/TelecomCallManager.kt index 2d161ca3b..aab9abc8c 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/TelecomCallManager.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/TelecomCallManager.kt @@ -61,6 +61,7 @@ object TelecomCallManager { /** Инициализация из ChatApplication.onCreate: регистрирует PhoneAccount. Идемпотентно. */ fun init() { + checkMain() if (ready) return try { val ctx = ChatApplication.instance @@ -129,6 +130,7 @@ object TelecomCallManager { /* ── реестр Connection (вызывается из UtunConnectionService) ── */ fun registerConnection(callId: Long, conn: UtunConnection): Boolean { + checkMain() val st = CallController.state.value if (st == null || st.callId != callId || !st.ongoing) { LogManager.addLog("WARN", TAG, "late connection for ended/stale call id=$callId current=${st?.callId}") @@ -173,14 +175,17 @@ object TelecomCallManager { /* ── управление состоянием из контроллера ── */ fun setRinging(callId: Long) { + checkMain() try { connections[callId]?.markRinging() } catch (e: Exception) { LogManager.addLog("ERROR", TAG, "ringing state failed id=$callId: $e") } } fun setActive(callId: Long) { + checkMain() try { connections[callId]?.markActive() } catch (e: Exception) { LogManager.addLog("ERROR", TAG, "active state failed id=$callId: $e") } } fun setDisconnected(callId: Long, reason: Int) { + checkMain() val conn = connections[callId] ?: return reasons[conn] = reason try { conn.markDisconnected(reason); disconnected.add(conn) } catch (e: Exception) { @@ -189,6 +194,7 @@ object TelecomCallManager { } fun removeConnection(callId: Long) { + checkMain() val conn = connections.remove(callId) if (conn != null) retire(callId, conn, reasons[conn] ?: 0) else cleanupConnections() LogManager.addLog("DEBUG", TAG, "connection removed id=0x%016x".format(callId)) @@ -218,6 +224,11 @@ object TelecomCallManager { /* ── helpers ── */ + private fun checkMain() = check(Looper.myLooper() == Looper.getMainLooper()) { + LogManager.addLog("ERROR", TAG, "Telecom owner mutation outside main") + "Telecom owner mutation requires main" + } + private fun telecomManager(): TelecomManager? { if (!ready) { LogManager.addLog("WARN", TAG, "Telecom request before account registration"); return null } return try { diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/UtunConnectionService.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/UtunConnectionService.kt index e7729071e..c88342757 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/UtunConnectionService.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/UtunConnectionService.kt @@ -16,13 +16,13 @@ import android.telecom.DisconnectCause class UtunConnectionService : ConnectionService() { override fun onCreateIncomingConnectionFailed(account: PhoneAccountHandle?, request: ConnectionRequest?) { - val id = request?.extras?.getLong(TelecomCallManager.EXTRA_CALL_ID, 0) ?: 0 + val id = requestId(request) LogManager.addLog("WARN", "UtunConnSvc", "Telecom rejected incoming call id=$id") TelecomCallManager.notifyConnectionFailed(id) } override fun onCreateOutgoingConnectionFailed(account: PhoneAccountHandle?, request: ConnectionRequest?) { - val id = request?.extras?.getLong(TelecomCallManager.EXTRA_CALL_ID, 0) ?: 0 + val id = requestId(request) LogManager.addLog("WARN", "UtunConnSvc", "Telecom rejected outgoing call id=$id") TelecomCallManager.notifyConnectionFailed(id) } @@ -33,6 +33,7 @@ class UtunConnectionService : ConnectionService() { ): Connection? { val (callId, peerNodeId, name) = parseRequest(request) ?: run { LogManager.addLog("WARN", "UtunConnSvc", "onCreateIncomingConnection: bad request extras") + TelecomCallManager.notifyConnectionFailed(requestId(request)) return Connection.createCanceledConnection() } LogManager.addLog("INFO", "UtunConnSvc", @@ -46,6 +47,7 @@ class UtunConnectionService : ConnectionService() { ): Connection? { val (callId, peerNodeId, name) = parseRequest(request) ?: run { LogManager.addLog("WARN", "UtunConnSvc", "onCreateOutgoingConnection: bad request extras") + TelecomCallManager.notifyConnectionFailed(requestId(request)) return Connection.createCanceledConnection() } LogManager.addLog("INFO", "UtunConnSvc", @@ -64,18 +66,26 @@ class UtunConnectionService : ConnectionService() { } } - private fun parseRequest(request: ConnectionRequest?): Triple? { - val extras = request?.extras ?: run { - LogManager.addLog("WARN", "UtunConnSvc", "connection request has no extras") - return null + private fun requestId(request: ConnectionRequest?): Long = try { + request?.extras?.getLong(TelecomCallManager.EXTRA_CALL_ID, 0) ?: 0 + } catch (e: Exception) { + LogManager.addLog("ERROR", "UtunConnSvc", "connection request ID decode failed: $e"); 0 + } + + private fun parseRequest(request: ConnectionRequest?): Triple? = try { + val extras = request?.extras + if (extras == null) { + LogManager.addLog("WARN", "UtunConnSvc", "connection request has no extras"); null + } else { + val callId = extras.getLong(TelecomCallManager.EXTRA_CALL_ID, 0L) + val peer = extras.getLong(TelecomCallManager.EXTRA_PEER_NODE_ID, 0L) + val name = extras.getString(TelecomCallManager.EXTRA_DISPLAY_NAME) ?: "" + if (callId == 0L || peer == 0L) { + LogManager.addLog("WARN", "UtunConnSvc", "connection request missing identity id=$callId peer=$peer; keys=${extras.keySet()}") + null + } else Triple(callId, peer, name) } - val callId = extras.getLong(TelecomCallManager.EXTRA_CALL_ID, 0L) - val peer = extras.getLong(TelecomCallManager.EXTRA_PEER_NODE_ID, 0L) - val name = extras.getString(TelecomCallManager.EXTRA_DISPLAY_NAME) ?: "" - if (callId == 0L) { - LogManager.addLog("WARN", "UtunConnSvc", "connection request missing call ID; keys=${extras.keySet()}") - return null - } - return Triple(callId, peer, name) + } catch (e: Exception) { + LogManager.addLog("ERROR", "UtunConnSvc", "connection request extras decode failed: $e"); null } }