r30 is the current NDK LTS; r29 is no longer supported. The NDK path
is part of the libhevtun cache key, so the cached libraries are rebuilt
with the new toolchain.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
64cc609 (2.16.0+24) -> d9dca26 (tag 2.18.0), 16 commits. Changes on
the paths the app uses:
- HevSocks5SessionUDP: skip datagrams without an address or with an
empty payload, and set the IPv4 address type for a fixed UDP peer
(c02e3fd)
- lwIP 2a11c14 -> e22c9d2: fix PRETEND handling of IPv6 extension
headers and fragments, validate UDP PRETEND packets before accepting
new sessions
- HevSocks5Tunnel: assert on the stop event write result (c362232)
The rest is tunnel code for Windows, macOS, FreeBSD and NetBSD, an
optional Windows-only tunnel.guid key, mapped DNS, the upstream AAR
build, docs and version bumps. JNI entry points, Android.mk/build.mk
and the config keys the app writes are unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
JUnit 4 is in maintenance mode, and 4.13.2 (February 2021) is its last
release. Move the unit tests to JUnit Jupiter 6.1.3: the JUnit BOM,
junit-jupiter and the Platform launcher replace junit:junit, and the
unit test tasks run on the JUnit Platform. The test sources change only
mechanically: imports, lifecycle annotations, TemporaryFolder to
@TempDir, and the message argument moved last in three assertions.
Jupiter skips an invalid @Test method, such as one that returns a
value, with only a warning, where JUnit 4 failed the run. Treat
discovery warnings as failures to keep that behavior.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
AGP 9.4.1 is in the AGP range Gradle 9.8.0 was tested with (9.0 to
9.5.0-alpha02). AGP 9.4 requires at least Gradle 9.6.0.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
mockito-kotlin shared the mockitoMockitoInline version key with
mockito-inline, which was discontinued after 5.2.0 because Mockito 5
made the inline mock maker the default in mockito-core. The shared key
kept mockito-kotlin on 5.2.0.
- org.mockito:mockito-inline 5.2.0 -> org.mockito:mockito-core 5.24.0
- org.mockito.kotlin:mockito-kotlin 5.2.0 -> 6.4.0, on its own key
On the test classpath mockito-core moves from 5.7.0 to 5.24.0 and
Byte Buddy from 1.14.9 to 1.17.7, so the unit tests also run on JDK 25.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Increase toast background opacity from 70% to 85% for all theme variants in Theme.kt. This improves readability and keeps toast notifications visually consistent without changing their content or behavior.
Pass the optional failure message from the service layer through `MainServiceEvent` and show it in `MainViewModel` when available. This preserves the existing generic error toast as a fallback while surfacing more specific startup failures to the user.
Refactor toast helpers to route through a shared dispatcher that first tries the app snackbar manager and falls back to Android Toasts on the main thread. This adds a `long` duration option across normal/success/error/info toast APIs and avoids posting to a new Handler for every message by reusing a single main-thread handler.
Move several save-time validation failures from toast messages to field error states in the server and subscription editors. Password validation now marks the relevant server form field, and subscription editing highlights invalid URLs and update intervals before save instead of relying on transient toasts.
Replace toast-only required-field validation with Compose text field error states across routing, server, subscription, and user asset editors. The shared form field now supports `isError` and supporting text so save actions can block invalid input and highlight missing remarks, address, port, and URL values directly in the form.
Replace hard-coded channel labels with dedicated resource names for the main service, subscription updates, and connection checks in all nine supported locales. Resolve names through AppLocaleManager for service and application contexts.
Reuse the existing channel when refreshing its localized name, preserving channel IDs and user-controlled importance, sound, vibration, and visibility. Apply initial defaults only to newly created channels and remove the obsolete hard-coded service-channel name.
Extract channel localization from local/talkback-all-10 without adding its transient-message channel, snackbar fallback, or accessibility announcement infrastructure.
Coil 2 had its last release in July 2024 (2.7.0); Coil 3 is the
maintained line and uses new coordinates, io.coil-kt.coil3, with the
package prefix coil3.
AppIconFetcher now returns ImageFetchResult with drawable.asImage(),
since Coil 3 models images through its own Image type. Fetcher,
Fetcher.Factory, Options, DataSource and the ImageRequest builder chain
keep the same shapes, so the rest is imports.
No network artifact is required: AppListItem is the only AsyncImage call
site and both callers pass icon = null, so every model is the local
appicon: request served by AppIconFetcher.
Coil 3.6.3 declares minSdkVersion 23 and ships no native code, so
neither minSdk 24 nor the four app ABIs are affected.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Expose the `remoteDNS` option (added in Xray-core 26.9.9) in the wireguard.
- Accepts a comma-separated list of IPv4/IPv6 addresses
- Accepts "local" as a single value to resolve via the device's
local DNS instead of routing lookups through the tunnel
- Falls back to WIREGUARD_LOCAL_REMOTE_DNS when the field is empty
(Xray-core upstream value)
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* Name the targets in deletion confirmations
Extract the visible named-confirmation wording from the accessibility assembly onto current upstream. Cover main-list profiles, standard and custom profile editors, policy groups, proxy-chain members, subscriptions, routing-rule editors, and asset sources. Reuse the six localized named variants in all nine catalogs; preserve existing generic strings and the already-named asset-file confirmation.
Carry display names alongside existing GUIDs in main/subscription list confirmation requests, and retain the main target across recreation with its two-string saver. Use saved names in editors rather than uncommitted renames. Do not import accessibility semantics, action menus, live regions, the separate routing-list Delete button, or the proxy-chain stable-key migration.
Validation: 72 JVM tests passed, including two deletion-target saver regressions; Play Store debug compilation and x86_64 assembly passed. An API 33 emulator verified all 54 compiled localized resources with Unicode and percent-containing names, the main profile confirmation across rotation, and subscription confirmation/cancel. No deletion was confirmed. Other editors, double-column menus, keyboard/D-pad, and TalkBack were not exercised. Original APK and rotation settings were restored.
* Standardize named delete confirmation layout
Center delete confirmation messages while retaining a single Text node for the question and target. Separate each item name with a blank line in all nine locales, including asset files, which previously embedded the filename in the question.
Keep the title-free dialog and existing Cancel/Delete actions, and leave ordinary confirmation messages start-aligned. Bulk-delete prompts retain their collective wording.
Validation: 72 JVM tests, Kotlin compilation and Play Store debug assembly passed. All 63 compiled localized templates preserved an exact Unicode/percent target. Emulator checks covered profile and asset message nodes, two action targets, cancellation and profile dialog recreation after rotation. Actual spoken TalkBack output and the full theme/input matrix were not verified.
* Resolve named proxy-chain confirmations by stable member key
Upstream #6200 replaced pending member indices with stable keys. The textual rebase of #6202 retained an out-of-scope index reference in the confirmation text, breaking compilation.
Look up the current member name through memberKeys, using the same pending identity as deletion. Reordering no longer separates the displayed target from the member removed on confirmation.
* Reuse deletion questions instead of duplicating named translations
Let DeleteConfirmDialog append an optional item name after a blank line while keeping the complete message in one centered Text. Reuse the existing localized questions at all named deletion sites and remove six duplicate resource keys from all nine locales. Asset-file questions use the same shared layout. Unnamed and bulk prompts remain unchanged.
Retain stable-key proxy-chain target lookup and the corrected Russian policy-group wording in the reused question. Validation: existing ServerDeleteTargetTest, all 79 JVM tests, x86_64 Play Store debug assembly and a Pixel 9 Pro emulator check passed. The profile dialog exposes one question/name text node plus Cancel/Delete, and canceling preserves the lab profiles. TalkBack was enabled for the smoke check; actual speech and the full device/theme/locale matrix were not independently verified.
Extract request ownership and cancellation from the accessibility work without changing result wording or presentation. Correlate current and bulk replies with the request that produced them so older progress, cancellation, and completion cannot finish a replacement test.
Own current probes in the core manager and cancel them on replacement, stop, or reload. Use the existing ordered service acknowledgement to retire requests when the daemon is absent. Cancel pending bulk preparation when the UI cancels or its ViewModel is cleared, and snapshot the filtered target list before asynchronous preparation.
Tag bulk cancellation per worker, including service destruction, instead of reporting cancellation as successful completion or issuing an untagged reply. Report rejected bulk-service starts through the same cancellation path. Preserve the existing service modes, IPC payload classes, and group post-test policy.
Validation: 74 JVM tests, Kotlin compilation and Play Store debug assembly passed. External emulator probes exercised current and bulk replacement, stale replies, cancellation during preparation, daemon-absent acknowledgement, and real notification-command cancellation over 15 Lab profiles. VPN smoke testing returned a current result with IP information and preserved disconnected status after stop. Root/proxy-only and network-handover runtime checks were not run.
Extract the config and asset update-result resources from local/talkback-all-10 in all nine supported locales. Describe completed updates instead of an update command, and select singular or plural forms using the actual config or successful asset count.
Route both subscription update entry points through the existing localized ViewModel context and use activity resources for asset results. Preserve update execution, counts, partial-failure summaries, error handling, and toast delivery; no accessibility announcement infrastructure is included.
Store the pending member key instead of its list position and resolve that key when deletion is confirmed. Remove the member and its corresponding row key together; if the target no longer exists, leave the draft unchanged.
Extract the deletion fix from the accessibility assembly without importing accessibility actions, dialog wording changes, or drag refactors. Reuse the same key-based removal for blank members.
Validation: 75 JVM tests passed, including five deletion regressions; Play Store debug Kotlin compilation and x86_64 assembly passed. Emulator smoke check covered confirmation across rotation and immediate blank-member removal. Keyboard/D-pad and runtime reorder-during-confirmation scenarios were not run.
Use a builtin: filename-based ID instead of generating a fresh UUID each time the asset list is rebuilt. This lets the existing GUID-keyed list and file-metadata map recognize the same built-in asset after reloads and download-source changes.
Extract the fix and its two JVM regression tests from local/talkback-all-10. Preserve stored asset GUIDs, matching built-in replacement, locked flags, and URL behavior. No persisted IDs, accessibility semantics, metadata formatting, or editor behavior are changed.
Extract the visible asset metadata formatting from local/talkback-all-10. Use Android file-size formatting and derive the date/time pattern from the app configuration locale and the device 12/24-hour preference, without seconds.
Remove the metadata-only remember cache so recomposition uses the current formatting context. Preserve the existing size/date separator, missing-file message, row layout, action buttons, and accessibility semantics. No update-result or asset-editor changes are included.
Move subscription QR bitmap generation from the synchronous share callback into the existing ViewModel, running CPU-bound encoding on Dispatchers.Default and exposing the completed bitmap through StateFlow.
Cancel pending result delivery when the dialog is dismissed, a newer share request replaces it, or the ViewModel is cleared. Keep dialog rendering lifecycle-aware and reuse the existing localized failure message when generation returns no bitmap.
Extract only QR generation and dialog-state wiring from local/talkback-all-10. Leave subscription row accessibility, custom actions, update handling, and clipboard sharing unchanged.
* Preserve asset-editor drafts and handle the keyboard
Keep the asset name, URL, and delete-confirmation visibility in saveable Compose state so activity recreation does not discard an unfinished edit. Key the state by asset identity and initial field values.
Make the form vertically scrollable, consume the Scaffold padding, and apply IME padding so its fields remain reachable when the keyboard reduces the available height. Extract these presentation changes from local/talkback-all-10 without changing accessibility labels, deletion wording, or asset-save validation order.
* Resize the asset editor when the keyboard opens
Declare stateUnchanged|adjustResize for UserAssetUrlActivity, matching the other editor activities. Without an explicit resize policy, opening the IME in landscape pans the entire window and moves the toolbar Save action off-screen despite the scrollable Compose form.
Verified on Android 13 Pixel 6a: rotate with an unsaved draft, reopen the landscape keyboard, scroll between fields, edit the first field, save without hiding the keyboard, and reopen persisted values. Portrait keyboard and Save also pass. Debug assembly succeeded.
Replace the short-lived info toast with the existing titleless confirmation dialog and a single OK button so users can read the routing explanation at their own pace. Keep dialog visibility in saveable screen state and reuse the existing localized help and action strings.
Extract only the help-dialog presentation from local/talkback-all-10; leave app-row semantics, switches, routing descriptions, and notification infrastructure in the accessibility branches.
Reject duplicate names and empty names or URLs before invalidating the existing asset cache. Previously a rejected save left the stored source unchanged but deleted its downloaded file.
Preserve the validation messages and their order, duplicate-name exclusion by asset ID, and successful-save behavior. Renames still invalidate the old filename before updating the asset record.
Standardizes manifest process names by replacing the long `:RunSoLibV2RayDaemon` suffix with `:daemon` for shortcut activities, VPN/proxy services, and related receivers. It also moves `CoreTestService` and `SubscriptionUpdateService` to a separate `:tasks` process to isolate task-oriented work from the main daemon process.
A saved SUB_IDS array can contain the same GUID more than once. Loading
it verbatim creates repeated subscription rows with identical Compose
and reorderable-list keys, which can crash the subscription screen.
Deduplicate IDs in the shared reader while preserving the first-seen
order and mutable-list contract. This protects every index consumer
without changing subscription records, generating replacement IDs, or
adding writes during reads. Different subscriptions with identical or
blank names remain separate.
Add six regression tests for duplicate rows, stable ordering, read-only
decoding, mutable round trips, repeated names, and existing empty/invalid
input behavior. Three assertions fail on unchanged upstream; all six
pass with the fix. The full 63-test suite and Play Store debug build pass.
On the API 37.1 Pixel 9 Pro emulator, a deliberately duplicated saved
index loaded each subscription once, retained first-occurrence order,
reopened safely, and edited the correct record. The raw index remained
duplicated throughout the check; no app crash was observed.
Logcat used the complete log text as a Compose lazy-list key after 258de2097. Identical timestamped messages and repeated stack frames are valid log output, but collide as keys and crash the main thread while browsing logs.
Give each occurrence its own key in a small ViewModel-owned presentation model. Count oldest-first so prepending newer logs and filtering unrelated lines retain existing occurrence keys. Build the projection off the main thread and keep raw text, duplicates, ordering, copy and share behavior unchanged.
Add six regression tests covering duplicate messages, repeated frames, filtering, refresh, empty input and key-like text. All 63 Play Store unit tests pass; the debug APK was checked on the API 37.1 emulator with duplicate-line scrolling, filtering, refresh, reopening and lossless export. The original failure is documented by the user-provided physical-device crash log.
Switch routing ruleset lookup, save, and delete flows from list index to stable ruleset ID. Routing edit intents now pass `ruleset_id`, editing reloads by ID, and list item edit actions use each rule’s ID. This avoids index mismatch bugs when list order changes and keeps update/delete targeting the correct ruleset.