Если приложение уже запущено (есть задача), launcher-активность добавляется
поверх неё. Добавлен guard isTaskRoot: в этом случае SplashActivity сразу
закрывается, текущий экран просто разворачивается — без splash и перезапуска.
Холодный старт (задача отсутствует) работает как прежде.
Засчитываем запуск лишь когда процесс создан заново (приложение было
выгружено), через флаг SvxApp.coldStart из SplashActivity. Выход из фона
и повторный тап по иконке (процесс жив) больше не учитываются. Время
последнего запуска пишем по Москве (формат ISO с офсетом +03:00).
Убрана зависимость lifecycle-process.
SvxApp.onCreate вызывается один раз на процесс, поэтому при живом
фоне повторные открытия не учитывались. Теперь считаем onStart
ProcessLifecycleOwner (холодный старт и каждое открытие приложения).
При старте приложения обновляет запись своего позывного во внешнем
документе: версия ПО, время последнего запуска и число запусков.
Записи других позывных не изменяются.
tryConnectOnce игнорировала результат runTcpLoop и всегда возвращала true,
из-за чего reconnectLoop не делал паузу и переподключался заново каждые
~30 мс, заваливая сервер MSG_ERROR 'Access denied'. Теперь возвращаем
!running, поэтому после разрыва/отказа выдерживается RECONNECT_DELAY_MS.
После короткого обрыва сервер ещё держит старую сессию и на рукопожатии
присылает MSG_ERROR. Клиент трактовал любую ошибку до STATE_READY как
фатальную (stopFatal → STATE_AUTH_FAILED) и прекращал переподключения.
Теперь ошибки рукопожатия (MSG_ERROR, протокольные сбои, слишком большой
кадр) считаются временными, если успешная сессия уже была (everReady):
показываем STATE_ERROR и продолжаем автопереподключение. Фатально — только
до первой успешной авторизации (реально неверные креды).
- Удалена надпись HOLD TO TALK (lbl_ptt_hint).
- PTT-кнопка увеличена 130→170 dp.
- Строка говорящего перенесена между блоками «на связи» и
индикаторами; единый формат: «Говорит UA1ZBE TG12» при приёме,
«UA1ZBE TG12» когда приёма нет (шрифт прежний).
- RxRecorder: MediaCodec(Opus) + MediaMuxer(OGG), пишет декодированный
RX PCM 48 кГц; pts не продвигается во время тишины, поэтому паузы
в эфире не попадают в файл.
- OpusEngine.rxTap: перехват PCM из выхода декодера.
- SvxService: startRecording()/stopRecording()/isRecording().
- MainActivity: кнопка btn_record между позывным и монитором,
индикация (иконка краснеет), тосты о старте/сохранении.
- Файлы: Android/data/ru.ua1zbe.svxremote/files/recordings/rec_*.ogg.
Пустой файл (весь сеанс — тишина) удаляется.