EN
New VPN client: Tunguska (PR #79 by @Acionyx)
Adds Tunguska as a managed VPN client. Token-based explicit-activity API instead of broadcast -- per-package tokens are stored in encrypted SharedPreferences. Anubis freezes the client in idle and unfreezes only around start/stop, same lifecycle as the other managed clients.
Stealth state no longer gets stuck "Enabling…"
If the external VPN client crashes mid-toggle, the orange "Включение…" banner used to spin forever. The orchestrator now runs enable/disable as a detached job inside app.scope, with withTimeoutOrNull(45 s) on job.join() -- Job.join() is genuinely cancellable, unlike a synchronous binder call inside withContext(Dispatchers.IO). After a timeout the state is reset to DISABLED, the user gets a "Operation timed out" message, and the UI is unblocked. Reduced from the 120 s ceiling in beta.1 -- that was long enough that users would force-stop the app first.
Stealth state no longer gets stuck "Enabled" after external VPN crashes
Companion fix to the one above: when the external VPN process dies asynchronously, _state is realigned with the real vpnActive flow via alignStateWithVpn() in finally, so the toggle never sits in a transitional state.
Background monitoring service is no longer killed by app launches (#65, #73)
VpnMonitorService was being started/stopped from MainViewModel, StealthTileService, StealthWidgetService, and the launch helpers -- every entry point was racing the user's "Background monitoring" setting. Service lifecycle is now strictly controlled by setBackgroundMonitoring() / loadBackgroundMonitoring(). If the user enabled monitoring, it stays on regardless of how apps are launched through Anubis.
anubis:// shortcuts launch on the first tap (follow-up to #9)
After unfreezeApp returns, PackageManager's launcher-intent cache lags 100–300 ms while it rebuilds, so getLaunchIntentForPackage would return null on the first call. Symptom: first tap on a shortcut did the group ops (VPN off, freeze/unfreeze) but didn't start the target activity; second tap worked because the app was already cached. launchApp is now a suspend function that polls every 50 ms with a 1.5 s ceiling -- already-launchable apps return on the first iteration with no delay.
MIUI / HyperOS -- VPN client broadcasts now include explicit -p (#66)
OEM am drops broadcasts without an explicit package filter. Adding -p <packageName> to the broadcast invocations makes intents reach the target client on Xiaomi / POCO firmwares. Closes the broadcast half of the OEM cluster (the freeze half was already addressed by Binder IPC in beta.1).
Recovery screen tab navigation (#87, PR #91)
Tabs on the Recovery screen now switch correctly. Was a state-handling bug introduced when the screen was added.
Dialog / bottom-sheet dismiss state (#90)
Dialogs and bottom-sheets correctly reset their dismiss state across recompositions -- fixes ghost dialogs that wouldn't reopen after dismissal. Thx for the PR @elagin
Other
- VPN settings page rewritten -- extracted from a Settings section into a dedicated tab, Hail-style search (parity with the Apps tab).
- Tink R8
-dontwarnrules added to suppress warnings from EncryptedSharedPreferences in release builds. BackHandleron the Recovery screen so back-press behaves consistently.
RU
Новый VPN-клиент: Tunguska (PR #79, @Acionyx)
Добавлен Tunguska как управляемый VPN-клиент. Token-based explicit-activity API вместо broadcast'ов -- токены на каждый пакет хранятся в зашифрованных SharedPreferences. Anubis замораживает клиент в idle и размораживает только на момент старт/стоп, тот же жизненный цикл, что и у остальных клиентов.
"Включение…" больше не висит вечно
Если внешний VPN-клиент падал в момент переключения, оранжевая плашка "Включение…" крутилась бесконечно. Оркестратор теперь запускает enable/disable как detached-job в app.scope, а withTimeoutOrNull(45 с) навешен на job.join() -- Job.join() корректно отменяется, в отличие от синхронного binder-вызова внутри withContext(Dispatchers.IO). По таймауту состояние сбрасывается в DISABLED, пользователь видит "Операция превысила таймаут", UI разблокирован. Снижено со 120 с в beta.1 -- за это время пользователь успевал нервно сделать force-stop.
"Включено" больше не залипает после краха внешнего VPN
Парный фикс: когда процесс внешнего VPN умирает асинхронно, _state синхронизируется с реальным vpnActive через alignStateWithVpn() в finally -- тоггл никогда не остаётся в промежуточном состоянии.
Фоновый мониторинг больше не убивается при запуске приложений (#65, #73)
VpnMonitorService стартовал/останавливался из MainViewModel, StealthTileService, StealthWidgetService и launch-хелперов -- каждая точка входа конкурировала с пользовательской настройкой «Фоновый мониторинг». Жизненный цикл сервиса теперь жёстко управляется только из setBackgroundMonitoring() / loadBackgroundMonitoring(). Если пользователь включил мониторинг -- он остаётся включённым вне зависимости от того, как запускаются приложения через Anubis.
Ярлыки anubis:// запускают приложение с первого тапа (follow-up к #9)
После unfreezeApp кэш launcher-intent в PackageManager лагает 100–300 мс, пока перестраивается -- getLaunchIntentForPackage возвращал null на первом вызове. Симптом: первый тап по ярлыку выполнял групповые операции (выкл VPN, заморозка/разморозка), но target activity не стартовала; второй тап работал, потому что приложение уже в кэше. launchApp теперь suspend-функция с polling каждые 50 мс и потолком 1.5 с -- уже-запускаемые приложения возвращаются на первой итерации без задержки.
MIUI / HyperOS -- broadcasts с явным -p (#66)
OEM-овский am отбрасывает бродкасты без явного package filter. Добавление -p <packageName> к броадкастам доводит intent'ы до целевого клиента на прошивках Xiaomi / POCO. Закрывает broadcast-половину OEM-кластера (freeze-половина уже была закрыта Binder IPC в beta.1).
Навигация по табам на экране Recovery (#87, PR #91)
Табы на экране Recovery теперь корректно переключаются. Был state-handling баг, появившийся при добавлении экрана.
Состояние закрытия диалогов / bottom-sheet'ов (#90)
Диалоги и bottom-sheet'ы корректно сбрасывают своё dismiss-состояние при рекомпозициях -- фиксит «призрачные» диалоги, которые не открывались повторно после закрытия. Спасибо за PR @elagin
Прочее
- Переписана страница настроек VPN -- вынесена из секции в Settings в отдельную вкладку с Hail-style поиском (паритет с вкладкой Apps).
- Добавлены
-dontwarnправила Tink R8 -- убирают warning'и от EncryptedSharedPreferences в release-сборках. BackHandlerна экране Recovery -- back-press теперь ведёт себя предсказуемо.