diff --git a/tools/chatgui-android/call-service-tests/src/main/kotlin/com/utun/chat/data/CallServiceHost.kt b/tools/chatgui-android/call-service-tests/src/main/kotlin/com/utun/chat/data/CallServiceHost.kt new file mode 100644 index 00000000..25a77534 --- /dev/null +++ b/tools/chatgui-android/call-service-tests/src/main/kotlin/com/utun/chat/data/CallServiceHost.kt @@ -0,0 +1,108 @@ +package com.utun.chat.data + +import android.content.Context +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Future +import kotlinx.coroutines.flow.MutableStateFlow + +/** Только DSP/camera/Telecom и чужие media. CallService/CallController/CoreActivity компилируются из приложения. */ +object AppLanguage { + var language = "en" + var failText = false + fun context() = com.utun.chat.ChatApplication.instance + fun text(id: Int): String { check(!failText) { "language unavailable" }; return "$language:$id" } +} + +class CallAudioEngine { + val router = CallAudioRouter() + var onFailure: ((Long, String) -> Unit)? = null + var failures = emptySet() + var active = false + var starts = 0; var stops = 0 + private var muted = false + val diagnostics: String get() { check("diagnostics" !in failures); return "host active=$active" } + fun start(id: Long): Boolean { + starts++ + if ("reject" in failures) return false + active = true + check("start" !in failures) { "audio start failed after effect" } + return true + } + fun stop() { + stops++ + check("stop" !in failures) { "audio stop unavailable" } + active = false + check("stop after" !in failures) { "audio stop failed after effect" } + } + fun isActive() = active + fun setMuted(value: Boolean) { muted = value } + fun isMuted() = muted + fun bindTelecom(connection: UtunConnection) {} + fun syncAecForRoute(route: AudioRoute) {} + fun outputLatency(id: Long) = CallOutputLatency() +} + +data class CallVideoSettings(val enabled: Boolean = false) +data class CallVideoState(val settings: CallVideoSettings = CallVideoSettings()) +class CallVideoEngine(context: Context, val id: Long) { + companion object { var failCreate = false; val created = mutableListOf() } + init { check(!failCreate) { "video constructor unavailable" }; created.add(this) } + var failures = emptySet() + var stopped = false; var stops = 0 + val state = MutableStateFlow(CallVideoState()) + val display = MutableStateFlow(null) + fun select(settings: CallVideoSettings) { state.value = CallVideoState(settings) } + fun stop() { + stops++ + check("stop" !in failures) { "video stop unavailable" } + stopped = true + check("stop after" !in failures) { "video stop failed after effect" } + } +} + +object TelecomCallManager { + interface Listener { + fun onConnectionAvailable(callId: Long, connection: UtunConnection) + fun onAnswer(callId: Long) + fun onReject(callId: Long) + fun onDisconnect(callId: Long) + fun onIncomingUiAllowed(callId: Long) + fun onConnectionFailed(callId: Long) + } + fun setListener(listener: Listener) {} + fun isReady() = false + fun placeCall(id: Long, peer: Long, name: String) {} + fun addIncomingCall(id: Long, peer: Long, name: String) = true + fun setActive(id: Long) {} + fun setDisconnected(id: Long, reason: Int) {} + fun removeConnection(id: Long) {} +} + +class ProximityManager(context: Context) { + val near = MutableStateFlow(null) + fun start() {} + fun stop() { near.value = null } +} +object RadioCallController { fun busy() = false } +object IncomingCallManager { + const val EXTRA_CALL_ID = "call_id" + const val CHANNEL_CALL = "incoming_call" + fun show(id: Long, channel: String, peer: Long) {} + fun stopRinging() {} +} +object CallRingback { fun stop() {}; fun startConnecting() {}; fun startRinging() {} } +object MicrophonePermission { + fun granted() = true + fun request(reason: String, callback: () -> Unit = {}) { callback() } +} +class RadioAudioEngine { + companion object { private val shared = RadioAudioEngine(); fun instance() = shared } + val activeGroup = MutableStateFlow(null) + val restored = mutableListOf() + fun stopForCall(): Future<*> { activeGroup.value = null; return CompletableFuture.completedFuture(Unit) } + fun restoreAfterCall(group: Long) { restored.add(group); activeGroup.value = group } +} +data class HostMediaState(val ongoing: Boolean) +object StreamController { val state = MutableStateFlow(null); fun stopForCall() { state.value = null } } +object StreamPlayerEngine { val viewing = MutableStateFlow(false); fun stopForCall() { viewing.value = false } } +object MediaAudioController { fun awaitIdle() {} } diff --git a/tools/chatgui-android/router-tests/src/main/kotlin/android/widget/Toast.kt b/tools/chatgui-android/router-tests/src/main/kotlin/android/widget/Toast.kt index 4a23f6ae..d96cee65 100644 --- a/tools/chatgui-android/router-tests/src/main/kotlin/android/widget/Toast.kt +++ b/tools/chatgui-android/router-tests/src/main/kotlin/android/widget/Toast.kt @@ -8,6 +8,7 @@ class Toast private constructor(val text: String) { const val LENGTH_LONG = 1 val shown = mutableListOf() fun makeText(context: Context, text: String, duration: Int) = Toast(text) + fun makeText(context: Context, resource: Int, duration: Int) = Toast("resource:$resource") } fun show() { shown.add(text) } }