Document Android radio invitation ownership, UI phases and fault checks

This commit is contained in:
evgeny committed 2026-10-29 13:34:23 +01:00
1 parent 6ec8950a85
commit 8100ea728e
2 files changed
+48 -1

No files matched your search

@@ -26,7 +26,10 @@ import com.utun.chat.data.RadioCallPhase
import com.utun.chat.data.RadioCallState
import com.utun.chat.ui.components.PortableRadioIcon
/** Как входящий звонок, рисуется внутри Activity, в том числе поверх keyguard. */
/** Полноэкранная карточка снимка RadioCallState внутри Activity; режим keyguard задаёт сама Activity.
* INCOMING предлагает accept/decline, WAIT_DECISION — продолжить/завершить. Во время PREPARING кнопок нет:
* Activity возвращает фактический результат включения рации через activated. ENDED показывает причину
* до удаления карточки контроллером. Компонент не владеет звуком, сигналингом или deadline вызова. */
@Composable
fun RadioCallDialog(state: RadioCallState) {
Box(Modifier.fillMaxSize().background(Color(0xCC000000)), contentAlignment = Alignment.Center) {
+44
View File
@@ -235,6 +235,43 @@ feed/pull workers и маршрутом Android Telecom; DSP и сетевой
Вызовы lifecycle DSP выполняются после остановки его внешних feed/pull callers.
Контракты PCM/PTS: `src/call/call_audio.h`, `src/radio/radio_audio.h`, `jni_bridge/android_jni_bridge.h`.
`RadioCallController` на main управляет адресным приглашением участника в обычную
рацию канала. Это отдельный сигналинг `src/radio/radio_call.h`, без отдельного
аудиозвонка. START резервирует busy до первого события ядра: быстрое повторное
нажатие не создаёт второй запрос, а CoreActivity удерживает активность также
на этом промежутке. Отказ очереди освобождает резерв, reset отменяет pending.
Событие 65 содержит ровно 27 little-endian байтов: id/group/peer по 8, затем
phase/reason/incoming по 1. ID ненулевые; Long хранит все биты uint64, строка
канала — десятичный uint64. Проверяются диапазоны и сочетания роли/фазы/причины,
а у своей попытки — вся тройка и incoming. Посторонние/устаревшие события не
меняют живую попытку и не публикуют результат от старой. При недоступных именах
repository UI использует ID, READY по-прежнему отправляется.
Входящий сначала публикует оповещение и отправляет READY. Ответ из уведомления
ждёт onStart Activity, разрешение микрофона перепроверяется; callbacks старой
попытки не принимают новую. Accept публикует PREPARING/activation, Activity
включает обычную рацию и возвращает activated(id, success). Только тогда входящий
отправляет ACCEPT либо FAIL и ждёт FINISHED. У исходящего ACCEPTED запрашивает
локальную активацию; её успешное завершение сразу снимает карточку. Поздние
RINGING/WAIT_DECISION/повторный FINISHED не откатывают исходящий PREPARING.
CONTINUE разрешён только своей WAIT_DECISION-попытке и сохраняет id.
Отказ/исключение JNI логируется с action/id/group/peer. Неотправленный READY,
ACCEPT/FAIL или CONTINUE завершает локальную попытку; DECLINE/CANCEL очищает UI
независимо от очереди. Блокирующая захват трансляция отправляет FAIL и закрывает
оповещение. Ошибка CoreActivity не прерывает сигналинг и независимую очистку:
CoreActivity сохраняет намерение для следующего sync. Deadline приглашения
остаётся в ядре; приложение владеет только отменяемой задержкой 2,5 с удаления
ENDED-карточки. Новая попытка/reset отменяет её, callback проверяет сам снимок.
Завершение приглашения не выключает обычную рацию. StateFlow повторяет текущие
state/activation для пересозданной Activity; история завершённых вызовов не
восстанавливается. RadioCallDialog отображает этот снимок и передаёт действия
контроллеру, не управляя deadline/аудио. Результат видимой Activity показывается
Toast, в фоне — отдельным уведомлением 1004, без замены уведомлений сервисов.
Отказ уведомления/локализации не мешает удалению карточки.
`RadioPttHolds` на main хранит по одному ручному удержанию BUTTON/OVERLAY/VOLUME.
Повтор press того же источника идемпотентен; несколько volume-клавиш агрегирует
Activity и отпускает общий VOLUME после последней клавиши. Release возвращает
@@ -512,6 +549,13 @@ native-эффектом, отказ feed/PTT/границы, отсутстви
после запроса новой группы. Проверяются освобождение подписок/encoder/track и
сохранение нового PTT. Android/JNI в этих сценариях моделируются на границах;
DSP, звуковое оборудование и сетевой эфир не запускаются.
RadioCallLifecycleTest использует настоящие RadioCallController, IncomingCallManager,
CoreActivity и гудки. Управляемые Android/JNI/repository-границы проверяют все
команды сигналинга, pending START, валидацию событий/полной identity, активацию,
старые callbacks/таймеры, PHONE_BUSY/CONTINUE, uint64 ID, отказы активности и
публикации результатов. IncomingCallLifecycleTest также использует настоящий
рационный контроллер при доставке DECLINE. Радиоэфир и C-сигналинг в JVM не
запускаются; native-протокол проверяется отдельным test_radio.
На Linux `:app:testDebugUnitTest` также запускает 25 fault-сценариев настоящего
JNI logger через `:app:testJniLog`; окружение и границы модели: `tests/jni_log/README.md`.
Проверки native bridge/standby доступны в `tests/Makefile.am`;