github sogonov/anubis 0.1.5.1
v0.1.5.1

5 hours ago

v0.1.5.1

This is the stable cut after the 0.1.5-beta.X series -- three weeks of feature work on top of 0.1.4.1, consolidated into one release. If you skipped the betas, this consolidates everything that landed since 0.1.4.1.

EN

Why "0.1.5.1" instead of "0.1.5"

The version comparator inside 0.1.5-beta.1 / beta.2 strips the pre-release suffix before comparing numeric parts, so it sees 0.1.5-beta.2 and 0.1.5 as identical and reports "you have the latest version". The fix lives in this release, but to break the deadlock we ship the stable as 0.1.5.1 -- the extra digit makes the old comparator detect the update. Future cycles (0.1.6-beta → 0.1.6 stable etc.) work correctly thanks to the fix; this digit-trick is one-off.

If you were on 0.1.4.1 / 0.1.5-beta.1 / 0.1.5-beta.2, regular auto-update will pick this build up.


OEM compatibility

Freeze rewritten to Binder IPC -- fixes HyperOS / MIUI / HiOS (#7, #33, #44, #58)

The freeze / unfreeze path now talks to IPackageManager.setApplicationEnabledSetting and IActivityManager.forceStopPackage directly via Shizuku Binder, instead of going through pm disable-user shell. OEM shells on HyperOS, MIUI, and HiOS silently no-op or hang on the shell command; the Binder path is untouched by vendor sandboxes. This is the single biggest change of the 0.1.5 cycle.

MIUI / HyperOS -- VPN client broadcasts now include explicit -p (#66)

OEM am drops broadcasts without an explicit package filter. Adding -p <packageName> to broadcast invocations makes intents reach the target client on Xiaomi / POCO firmwares.

Launcher safe mode (#103)

Optional setting that slows down mass-unfreeze (one app at a time with a short pause), reducing duplicate-shortcut glitches on misbehaving OEM launchers.

Extended non-freezable protection list (#104)

Built-in blocklist now covers more system input methods, accessibility services, and authenticators -- these are never frozen regardless of group assignment, on any firmware.


New VPN clients

Tunguska (PR #79 by @Acionyx)

Token-based explicit-activity API instead of broadcast -- per-package tokens are stored in EncryptedSharedPreferences. Anubis freezes the client in idle and unfreezes only around start / stop. First-class managed client, same lifecycle as the rest.

FlClash and FlClashX (#97)

Both forks are wired up in SEPARATE mode through their exported TempActivity -- independent start/stop without external auth, same idea as Clash Meta. The am start invocation includes --activity-multiple-task --activity-no-history --activity-no-animation so the user lands back where they came from instead of staring at FlClash's main UI for half a second.

Note on Tailscale

Tailscale advertises a public broadcast API, but the upstream StartVPNWorker calls setExpedited() without overriding getForegroundInfo() -- workers crash on devices that grant expedited quota. Tailscale will land once that's fixed upstream.


Reliability and state-machine fixes

Stealth state no longer gets stuck "Enabling…"

If the external VPN client crashed mid-toggle, the orange "Включение…" banner used to spin forever. The orchestrator now runs enable / disable as a detached job in 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.

Stealth state no longer gets stuck "Enabled" after external VPN crashes

When the external VPN process dies asynchronously, _state is realigned with the real vpnActive flow via alignStateWithVpn() in finally -- 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.

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 but didn't start the target activity; second tap worked. launchApp now polls every 50 ms with a 1.5 s ceiling -- already-launchable apps return on the first iteration with no delay.

Update checker -- release > pre-release per semver, beta channel default by build flavor

The version comparator now treats 0.1.5 as newer than 0.1.5-beta.2 (was returning equal). The "Включая бета-версии" toggle defaults to true for builds with a - suffix in the version name, so beta-X users automatically see beta-(X+1).


Big new features

Home screen widget

One-tap stealth toggle directly from the launcher. Shows live status ("Stealth ON / OFF") with intermediate states during freeze and VPN connect. Widget and QS tile always return to the real VPN state even if an operation hangs -- freeze calls have a 5 s per-app timeout, and the whole toggle has a 90 s hard ceiling.

Operation journal (#136)

A diagnostic log of freeze / unfreeze / VPN events visible at Settings → Журнал. Two follow-up controls:

  • Disable journaling entirely if it's not useful (Settings → "Запись журнала"). Existing entries stay viewable.
  • Share button in the journal viewer writes a snapshot to cacheDir and exposes it via FileProvider -- file is shared whole, no Binder transaction-size truncation that EXTRA_TEXT would impose.

Settings and groups export / import (#131)

Settings → "Экспорт настроек" / "Импорт настроек". Group memberships and the small set of plain-prefs settings snapshot to a JSON file via SAF. Import offers Replace (clear current groups first) or Merge (only add packages not already managed). Tunguska automation tokens are deliberately excluded so the export file is safe to share or store unencrypted.

anubis:// URL scheme (#9)

Launch any managed app via anubis://<packageName> -- works with Tasker, AppFolderWidget, and other launchers. The handler now surfaces a toast when the requested package is not installed or hasn't been added to any group, instead of silently doing nothing -- easier to debug Tasker tasks and widget configurations.

Multi-select app assignment (#80)

Assign multiple apps to a group in one operation.

Direct group selection in the long-press sheet (#78)

Long-pressing an app icon on Home opens the action sheet with all four groups listed and the current one checkmarked -- tap to switch. Replaces the tap-to-cycle pattern that was easy to overshoot. The cycle behavior is still available; this is an additional way in.

Mass unfreeze without clearing groups (#142, #144)

Recovery → "Разморозить всё (группы сохранятся)" thaws everything in one go but leaves group memberships intact. Useful for ad-hoc package updates or one-time use of a VPN_ONLY app without VPN. The next VPN state transition reapplies the group rules.

A persistent "pause" mode (where the orchestrator stops reacting to triggers entirely -- issue #114) is intentionally not in this release; it's a deliberate architectural feature for 0.1.6.

Pre-release update channel

Settings → "Проверять обновления" → "Включая бета-версии" subscribes to the pre-release feed. Default depends on the build (see Reliability section above).


Safety

Cleanup of traces left by uninstalled apps (#64, #141)

When a managed app is uninstalled through standard Android tools, its row in the group list and its pinned shortcut on the launcher used to linger. New PACKAGE_FULLY_REMOVED receiver drops the row from the database and disables the pinned shortcut -- most launchers prune disabled shortcuts on next refresh, and at minimum the dead icon stops being tappable.

Manual unfreeze warning for LOCAL apps (#81)

When VPN is active, manually unfreezing an app that belongs to a "local-only" group now shows a confirmation dialog explaining that the app's traffic will leak through the active VPN. The bulk freeze action is unaffected.

Shizuku status -- clearer states, one-tap recovery (#84, #85)

The single "unavailable" status was split into NOT_INSTALLED / NOT_RUNNING / NO_PERMISSION / READY. The Shizuku card on Home and Settings is clickable in every non-ready state -- opens the download page, launches the Shizuku app, or requests permission. Inactive Shizuku notifications now also surface across the app where relevant (#122).


Removed

"Размораживать группы при включении/отключении VPN"

The deprecated global toggle is gone. The per-group "Без VPN + уведомления" (LOCAL_AUTO_UNFREEZE) covers the actual use case more granularly. Behavior change: VPN_ONLY no longer auto-unfreezes when VPN starts, and LOCAL no longer auto-unfreezes when VPN stops. If you relied on auto-unfreeze, move those apps into the "Без VPN + уведомления" group.


Other

  • Apps tab: fixed list layout collapse and stale "frozen" labels (#117, #126).
  • Home: trailing 8 dp gap removed under the last row of group icons (#124).
  • Group management UX improved across Home and the app list (#129).
  • VPN settings page extracted from a Settings section into its own tab with Hail-style search.
  • Recovery screen tab navigation fixed (#87, #91), BackHandler for predictable back-press.
  • Dialog and bottom-sheet dismiss state correctly resets across recompositions (#90).
  • Default app sort: GROUP → PACKAGE (groups stay together).
  • Own dummy VPN now filtered by ownerUid instead of a time-based flag -- more reliable force-disconnect detection.
  • QS tile and entry points use awaitUserService() instead of delay(200) -- noticeably faster on warm Shizuku.
  • arrow literal replaced with KeyboardArrowRight icon -- fixes glyph rendering on MIUI / HyperOS.
  • README / repository documentation: Tunguska integration notes (#102), supported clients table rewritten with Full / Auto-toggle / Manual breakdown, FlClash + FlClashX rows, jadx discovery instructions, background-monitoring documented.
  • Tink R8 -dontwarn rules for EncryptedSharedPreferences in release builds.
  • Codebase-wide lint pass -- KTX idioms (PR #83 by @elagin).
  • Internal refactors: icon rendering, AppLogger, Shizuku check ordering, deprecated allNetworks API removal.

RU

Почему 0.1.5.1, а не 0.1.5

Внутри 0.1.5-beta.1 / beta.2 версионный компаратор обрезает pre-release-суффикс перед численным сравнением -- 0.1.5-beta.2 и 0.1.5 он считает идентичными и говорит у вас последняя версия. Фикс в этом релизе, но чтобы разорвать цепочку, stable выходит как 0.1.5.1 -- лишняя цифра заставляет старый компаратор увидеть обновление. Будущие циклы (0.1.6-beta → 0.1.6 stable и т.д.) поедут корректно благодаря фиксу; этот трюк с цифрой -- разовый.

Если вы на 0.1.4.1 / 0.1.5-beta.1 / 0.1.5-beta.2 -- обычное авто-обновление подтянет этот билд.


OEM-совместимость

Заморозка переписана на Binder IPC -- должно починить HyperOS / MIUI / HiOS (#7, #33, #44, #58)

Заморозка и разморозка теперь напрямую дёргают IPackageManager.setApplicationEnabledSetting и IActivityManager.forceStopPackage через Shizuku Binder вместо pm disable-user через shell. OEM-оболочки на HyperOS, MIUI и HiOS молча игнорируют или зависают на shell-команде; Binder-путь вендорными sandbox-ами не затрагивается. Самое крупное изменение цикла 0.1.5.

MIUI / HyperOS -- broadcasts с явным -p (#66)

OEM-овский am отбрасывает бродкасты без явного package-фильтра. Добавление -p <packageName> к броадкастам доводит intent'ы до целевого клиента на прошивках Xiaomi / POCO.

Безопасный режим лаунчера (#103)

Опциональная настройка, замедляющая массовую разморозку (по одному приложению с короткой паузой) -- снижает вероятность дублирующихся ярлыков на проблемных OEM-лаунчерах.

Расширен список приложений, защищённых от заморозки (#104)

Встроенный блок-лист теперь охватывает больше системных IME, accessibility-сервисов и аутентификаторов -- они никогда не замораживаются вне зависимости от группы и прошивки.


Новые VPN-клиенты

Tunguska (PR #79, @Acionyx)

Token-based explicit-activity API вместо broadcast'ов -- токены на каждый пакет хранятся в EncryptedSharedPreferences. Anubis замораживает клиент в idle и размораживает только на момент start / stop. Полноценный управляемый клиент, тот же жизненный цикл что и у остальных.

FlClash и FlClashX (#97)

Оба форка подключены в режиме SEPARATE через их exported TempActivity -- независимые start / stop без внешней авторизации, тот же подход что у Clash Meta. К am start добавлены флаги --activity-multiple-task --activity-no-history --activity-no-animation, чтобы юзер возвращался туда, откуда нажал, а не таращился полсекунды на главный экран FlClash.

Про Tailscale

У него заявлен публичный broadcast API, но апстримный StartVPNWorker зовёт setExpedited() без override getForegroundInfo() -- воркеры падают на устройствах с expedited-квотой. Tailscale приедет когда это починят в апстриме.


Надёжность и state-machine

Включение… больше не висит вечно

Если внешний VPN-клиент падал в момент переключения, оранжевая плашка Включение… крутилась бесконечно. Оркестратор теперь запускает enable / disable как detached-job в app.scope, а withTimeoutOrNull(45 с) навешен на job.join() -- Job.join() корректно отменяется, в отличие от синхронного binder-вызова внутри withContext(Dispatchers.IO). По таймауту состояние сбрасывается в DISABLED, пользователь видит Операция превысила таймаут, UI разблокирован.

Включено больше не залипает после краха внешнего VPN

Когда процесс внешнего VPN умирает асинхронно, _state синхронизируется с реальным vpnActive через alignStateWithVpn() в finally -- тоггл никогда не остаётся в промежуточном состоянии.

Фоновый мониторинг больше не убивается при запуске приложений (#65, #73)

VpnMonitorService стартовал / останавливался из MainViewModel, StealthTileService, StealthWidgetService и launch-хелперов -- каждая точка входа конкурировала с пользовательской настройкой Фоновый мониторинг. Жизненный цикл сервиса теперь жёстко управляется только через setBackgroundMonitoring() / loadBackgroundMonitoring(). Включил мониторинг -- он остаётся включённым вне зависимости от того, как запускаются приложения.

Ярлыки anubis:// запускают приложение с первого тапа (follow-up к #9)

После unfreezeApp кэш launcher-intent в PackageManager лагает 100–300 мс, пока перестраивается -- getLaunchIntentForPackage возвращал null на первом вызове. Симптом: первый тап выполнял групповые операции, но target-activity не стартовала; второй тап работал. launchApp теперь polling каждые 50 мс с потолком 1.5 с -- уже-запускаемые приложения возвращаются на первой итерации без задержки.

Проверка обновлений -- release > pre-release по semver, beta-канал по умолчанию определяется типом сборки

Версионный компаратор теперь считает 0.1.5 новее чем 0.1.5-beta.2 (раньше возвращал равны). Toggle Включая бета-версии по умолчанию true для сборок с - в имени версии, поэтому beta-X юзеры автоматом видят beta-(X+1).


Крупные новые фичи

Виджет на рабочий стол

Stealth-переключатель одним нажатием с лаунчера. Показывает живой статус (Stealth ON / OFF) и промежуточные состояния в процессе заморозки и подключения VPN. Виджет и плитка всегда возвращаются в реальное состояние VPN, даже если операция зависла -- у каждого binder-вызова таймаут 5 с, у всей операции -- 90 с.

Журнал операций (#136)

Диагностический журнал событий заморозки / разморозки / VPN доступен в Settings → Журнал. Два сопутствующих контрола:

  • Возможность отключить запись журнала, если она не нужна (Settings → Запись журнала). Уже записанные события остаются доступны для просмотра.
  • Кнопка Поделиться в просмотрщике журнала пишет снапшот в cacheDir и отдаёт через FileProvider -- файл уезжает целиком, без обрезок Binder transaction-size, которые накладывает EXTRA_TEXT.

Экспорт и импорт настроек / групп (#131)

Settings → Экспорт настроек / Импорт настроек. Группы и небольшой набор plain-prefs настроек выгружаются в JSON через SAF. При импорте на выбор: Заменить (очистить текущие группы и применить импортируемые) или Объединить (добавить только пакеты, которых нет в группах). Токены автоматизации Tunguska намеренно не включаются -- экспортный файл безопасно хранить и пересылать незашифрованным.

URL-схема anubis:// (#9)

Запуск любого управляемого приложения через anubis://<packageName> -- совместимо с Tasker, AppFolderWidget и другими лаунчерами. Если запрошенное приложение не установлено или не добавлено ни в одну группу, теперь показывается toast вместо тихого no-op -- проще дебажить Tasker-задачи и настройки виджетов.

Множественный выбор при назначении группы (#80)

Назначать несколько приложений в группу теперь можно за одну операцию.

Прямой выбор группы в long-press меню (#78)

Долгое нажатие на иконку приложения на Home открывает action-меню, в котором теперь видны все четыре группы с галочкой на текущей -- тапом меняется. Заменяет паттерн tap-to-cycle, в котором легко проскочить нужную. Цикл по тапу остался; это просто дополнительный путь.

Массовая разморозка без удаления из групп (#142, #144)

Recovery → Разморозить всё (группы сохранятся) размораживает разом всё, оставляя приложения в их группах. Удобно для разовых обновлений пакетов или временного использования VPN_ONLY-приложения без VPN. При следующем переключении VPN правила групп применятся заново.

Постоянный pause-режим (когда оркестратор не реагирует на триггеры в принципе -- issue #114) сюда не вошёл намеренно -- это полноценная архитектурная фича для 0.1.6.

Канал бета-обновлений

Settings → Проверять обновленияВключая бета-версии подписывает на pre-release фид. Default зависит от типа сборки (см. секцию Надёжность выше).


Безопасность

Чистка следов от удалённых приложений (#64, #141)

Когда управляемое Anubis приложение удалялось штатными средствами Android, оставались строка в группе и pinned-ярлык на лаунчере. Новый receiver PACKAGE_FULLY_REMOVED дропает запись из БД и отключает pinned-ярлык -- большинство лаунчеров чистят отключённые при следующем рефреше, и как минимум по мёртвой иконке нельзя ткнуть.

Предупреждение при ручной разморозке LOCAL-приложений (#81)

При активном VPN ручная разморозка приложения из локальной группы теперь показывает диалог-подтверждение с предупреждением, что трафик утечёт через активный VPN. Массовая заморозка не затронута.

Статус Shizuku -- понятные состояния и действие в один тап (#84, #85)

Единый статус недоступен разнесён на NOT_INSTALLED / NOT_RUNNING / NO_PERMISSION / READY. Карточка Shizuku кликабельна в любом не-готовом состоянии -- открывает страницу загрузки, запускает Shizuku или запрашивает разрешение. Уведомления о неактивном Shizuku теперь также появляются в релевантных местах приложения (#122).


Удалено

Размораживать группы при включении/отключении VPN

Старый глобальный переключатель убран. Group-level Без VPN + уведомления (LOCAL_AUTO_UNFREEZE) покрывает реальный сценарий точнее. Изменение поведения: VPN_ONLY больше не размораживается автоматом при включении VPN, а LOCAL -- при выключении. Если вы полагались на автоматическую разморозку, перенесите такие приложения в группу Без VPN + уведомления.


Прочее

  • Вкладка Apps: исправлены коллапс layout'а и устаревшие лейблы заморожено (#117, #126).
  • Home: убран лишний 8 dp gap под последним рядом иконок групп (#124).
  • Улучшен UX управления группами на Home и в списке приложений (#129).
  • Страница настроек VPN вынесена из секции в отдельную вкладку с Hail-style поиском.
  • Исправлена навигация по табам на экране Recovery (#87, #91), BackHandler для предсказуемого back-press.
  • Состояние закрытия диалогов и bottom-sheet'ов корректно сбрасывается при рекомпозициях (#90).
  • Дефолтная сортировка приложений GROUP → PACKAGE (группы остаются вместе).
  • Собственный dummy VPN фильтруется по ownerUid вместо флага по времени -- более надёжное определение принудительного отключения.
  • Плитка QS и точки входа используют awaitUserService() вместо delay(200) -- заметно быстрее при тёплом Shizuku.
  • Литерал-стрелочка заменена на иконку KeyboardArrowRight -- лечит рендер на MIUI / HyperOS.
  • Документация в репозитории: заметки про Tunguska integration (#102), таблица поддерживаемых клиентов переписана с разбиением на Full / Auto-toggle / Manual, добавлены строки FlClash + FlClashX, инструкции по jadx-discovery, описан фоновый мониторинг.
  • -dontwarn правила Tink R8 -- убирают warning'и от EncryptedSharedPreferences в release-сборках.
  • Чистка по всей кодовой базе -- KTX-идиомы (PR #83, @elagin).
  • Внутренние рефакторинги: рендер иконок, AppLogger, порядок проверок Shizuku, удаление deprecated allNetworks API.

Don't miss a new anubis release

NewReleases is sending notifications on new releases.