* Localize runtime-generated UI text
Keep connection-test and status data locale-neutral until the UI formats it, and localize delay units at their Compose presentation boundary.\n\nShow stable localized failures while retaining diagnostic exceptions in Logcat. Clarify routing rule matching and subscription entry/exit proxy behavior at the relevant UI call sites, and remove the now-unused core error resources.
* Fix Compose resource lookup in routing editor
* Adjust string
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* Refine existing locale translations
Carry over the standalone wording and translation corrections from the combined localization audit across all nine maintained catalogs.
Keep identifiers, order, placeholders, and metadata unchanged. Exclude resource additions, removals, and wording that depends on locale API, connection-result, routing layout, subscription proxy, delay-unit, or core code changes.
* Clarify profile export actions
Distinguish copying a profile share link from copying the fully generated configuration in every maintained locale.
Use AndroidX and framework per-app locale APIs, migrate the existing language preference, and expose the generated locale config to Android 13+ settings.
Resolve resources through the selected app locale in application, ViewModel, tile, and service contexts. Replace the framework OK and Cancel labels directly implicated in the wrong-language report, and refresh retained localized UI state after locale changes.
* fix: localize UI and accessibility text
* fix: translate BQI core errors
* fix: correct Bakhtiari orthography and wording
Replace the remaining Persian confirmation fallbacks, correct stale or mismatched UI meanings, and normalize established Bakhtiari terms without translating xray-core identifiers.
Primary source: Erik Anonby and Ashraf Asadi, Bakhtiari Studies II: Orthography (2018), sections 6.1.1, 6.8.1, 6.8.2, 6.8.7, and 6.8.9. https://www.diva-portal.org/smash/get/diva2%3A1231755/FULLTEXT02.pdf
The standard recommends that "Arabic letters be retained for Bakhtiari words borrowed from Persian" and reports that speakers view soft d as "a defining feature of how the language is pronounced."
Lexicon and phonology source: Erik Anonby and Ashraf Asadi, Bakhtiari Studies: Phonology, Text, Lexicon (2014). https://uu.diva-portal.org/smash/record.jsf?pid=diva2%3A758171
Historical corroboration: D. L. R. Lorimer, The Phonology of the Bakhtiari, Badakhshani, and Madaglashti Dialects of Modern Persian (1922). https://archive.org/details/phonologyofbakht06loriuoft
* fix: keep protocol description technical
* fix: keep Logcat diagnostics unlocalized
* getRemoteIPInfo
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* Use typed actions for application menus
* Use Material 3 navigation drawer components
Replace the custom drawer rows with NavigationDrawerItem and route system Back through Compose so an open drawer closes before the task is backgrounded.
* Polish typed menus and drawer integration
Move manual subscription updates to WorkManager-based background jobs and simplify scheduler logic by handling auto-update checks in `scheduleOne`. Add post-update server testing support with optional invalid-node cleanup and sorting, plus MMKV/AngConfig helpers to remove multiple servers and reorder subscription servers by test delay. Update the subscriptions UI flow and zh-TW strings to reflect background execution and new auto-test options.
* add composeui dependencies and component
* remove multidex
* BaseComponentActivity and HelperBaseComponentActivity
* migrate AppPicker/PerAppProxy Activity and use Snackbar
* migrate AboutActivity to composeui
* migrate BackupActivity to composeui
* migrate CheckUpdateActivity to composeui
* migrate Logcat to composeui
* migrate Scanner to composeui and camerax
* migrate sc start/stop/switch to compose
* migrate TaskerActivity to composeui
* migrate UrlSchemeActivity to composeui
* migrate UserAsset to composeui
* migrate ServerActivity to composeui
* migrate ServerCustomConfigActivity to composeui
* migrate ServerGroupActivity to composeui
* migrate ServerProxyChainActivity to composeui
* migrate SettingsActivity to composeui
* migrate SubEdit/SubSetting Activity to composeui
* migrate routingEdit/routingSetting Activity to composeui
* migrate MainActivity to composeui
* clode clean and chore change
* Fix
* add scrollbar
* fix imePadding
* fix FormDropdownField scrollbar and ime conflict
* update servercostomconfigactivity with linenum and scrollbar
* fix AppPickerActivity filter wrong toogle
* fix App theme xml
* fix scrollbar not work in SettingsActivity
* final inset
* fix servercustomconfigactivity when open not begin line
* try optimize mainactivity performance
* use launch intent and fix not refresh when second edit use equals
* fix a ghost error
* update string
* update miss string
* optimize mainactivity and mainviewmodel
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* feat: add a root, system-wide run mode without VpnService
Adds an optional Root mode for rooted devices that routes the whole device's
traffic through the existing in-process core without Android's VpnService, plus
an opt-in LAN/tethering sharing feature. Non-root devices are unaffected and keep
VPN / Proxy-only (VPN stays the default).
- ERunMode (VPN, PROXY_ONLY, TUN2SOCKS) persisted in the existing PREF_MODE;
RootManager gates root modes (greyed-out for non-root, service refuses to start).
- CoreRootService + core/root/RootProxyManager run hev-socks5-tunnel as a
standalone root process into the core's SOCKS inbound, steered by an iptables
mangle MARK chain + a dedicated route table. Full TCP + UDP. hev-socks5-tunnel
is the same engine already bundled for the VPN hev path, so no new third-party
dependency is added.
- Capture parity with VpnService incl. per-app proxy/bypass; DNS funneled into the
core (netd-aware, no uid filter) so names resolve through the configured
resolver with no LAN-resolver leak.
- IPv6 parity: routed into the tun when enabled, otherwise native v6 is blackholed
for the captured apps (REJECT) so they fall back to v4-through-proxy, like a
v4-only VpnService.
- MTU taken from the existing VPN MTU setting; hev tun multi-queue + SOCKS
tcp-fastopen enabled.
- CI fetches the hev-socks5-tunnel binary per-ABI from heiher/hev-socks5-tunnel
releases (the same upstream the VPN hev path uses).
* build: compile libhevsockstun.so from source instead of downloading
Build the standalone hev-socks5-tunnel binary used by Root mode from the
pinned hev-socks5-tunnel submodule in compile-hevtun.sh, alongside the
existing JNI shared library, and drop the prebuilt release download from
the build workflow.
Both hev artifacts now come from the same in-tree source, so the binary
is fully auditable and version-locked to the submodule rather than a
fetched release asset. The executable is built without -DENABLE_LIBRARY
(so hev-main.c's main() is included) via BUILD_EXECUTABLE, reusing the
NDK toolchain already used for the JNI library.
* refactor(root): address review feedback
- LAN-sharing guard now checks the cheap, usually-false PREF_ROOT_LAN_SHARING
preference before RootManager.cachedRoot(), so the common path short-circuits
without touching root state.
- Move RootManager into the core.root package next to RootProxyManager and
RootShell (CoreRootService stays under service/).
- Probe su only when the user opts into a root feature — selecting a root mode
or enabling LAN sharing — instead of automatically on every Settings open.
If root is denied the selection is reverted with a toast. This avoids an
unsolicited root-grant prompt for the common non-root case; root mode for a
persisted selection is still re-verified when the service starts.
* refactor(root): use coroutines instead of Thread for su probing
Replace raw Thread usage in the root path with kotlinx coroutines, as
requested in review. RootManager.refreshAsync (a callback + daemon Thread)
becomes a suspending refresh() that runs the blocking su probe on
Dispatchers.IO and returns the result.
Callers updated accordingly:
- SettingsActivity probes on demand via lifecycleScope.launch and updates
the UI directly on resume (no manual runOnUiThread).
- CoreVpnService starts the LAN-sharing client over CoroutineScope(IO)
instead of a daemon Thread.
* fix(root): don't capture all apps when per-app proxy resolves no uids
In allow (proxy-only) mode the mangle/v6 builders fell through to the
catch-all "mark/reject everything" branch whenever selectedUids was empty.
That is a fail-open: if the selected packages momentarily fail to resolve to
uids (e.g. at early boot, before PackageManager is ready), every unselected
app gets tunneled instead of none — a privacy leak and the cause of per-app
"proxying everything" after a reboot.
Gate the catch-all on the mode itself (all-apps or bypass) rather than on
"selected list happened to be non-empty". In allow mode mark only the
resolved uids; if none resolved, mark nothing (fail closed). Mirror the same
fix in the IPv6 blackhole chain.
* fix(root): wait for async rule setup before teardown on stop
CoreRootService/CoreVpnService post the foreground notification as soon as the
core starts but install the root routing rules in a launched coroutine, which
can take seconds (the setup script waits for the tun device to appear). If the
user stops the service during that window, onDestroy/stopAllService ran the
synchronous teardown first and the still-running setup then re-installed the
rules and tun afterwards — leaving orphan routing rules and a tun forwarding
into a now-dead core, which blackholes all traffic until the next start/stop
cycle clears it (the "disconnect from the notification kills the internet,
reconnect+disconnect to fix it" bug).
Track the setup job and cancelAndJoin it before tearing down so teardown always
runs last and removes everything the setup installed.
* Adjust root package and add RootLanSharing object
* Remove ERunMode , add PREF_ROOT_MODE_ENABLE
* fix(root): handle tethered clients' IPv6 in LAN sharing to stop leaks
LAN/tethering sharing only set up IPv4 forwarding for clients, so a
hotspot/USB-tethered client with a native (RA-assigned) global IPv6
egressed the upstream interface directly, bypassing the proxy — an
IPv6 leak.
buildLanShareSetup now handles forwarded clients' v6:
- IPv6 enabled: route it through the tun. A mangle PREROUTING chain
marks non-LOCAL-sourced (forwarded) v6 into the tun route table,
keeps loopback/link-local/ULA/multicast direct, and hijacks client
DNS; FORWARD accepts traffic to/from the tun. A trailing REJECT
fails closed so anything not marked into the tun (e.g. addrtype
match unavailable) is dropped instead of leaked.
- IPv6 disabled: REJECT all forwarded v6 (the device's own v6 is
already blackholed in OUTPUT).
Teardown drops the two new ip6tables chains; the v6 route/rule into
the tun table were already cleaned.
Ported from vincentng295/Magic_V2Ray cae4f7f.
* Update build.gradle.kts
* Adjust settings
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
Add a new "Share log" menu item in Logcat.The action creates a temporary .txt file from the current log output and opens the Android share sheet, allowing users to save or send logs to other apps.
Introduce a configurable concurrency for real-ping (true delay) tests. Add PREF_REAL_PING_CONCURRENCY and DEFAULT_REAL_PING_CONCURRENCY in AppConfig, a getter SettingsManager.getRealPingConcurrency() (parses stored value, defaults to 16, clamps to 1..128), and use that value to create the RealPingWorkerService thread pool instead of cpu * 4. Expose the setting in preferences (EditTextPreference) and add localized title strings across multiple resource files. This lets users control how many concurrent real-ping workers run.
Introduce a new Proxy Chain server type and full support across UI and core logic. Added EConfigType.PROXYCHAIN and ProfileItem.proxyChainProfiles, new ServerProxyChainActivity, ServerProxyChainMemberAdapter, layouts and menu entries, and localized strings. CoreConfigContextBuilder now resolves proxy-chain members (from explicit list or subscription group) with robust filtering and error logging; CoreConfigManager validates chain length and logs warnings. CoreOutboundBuilder and CoreServiceManager were updated to treat PROXYCHAIN as a non-directly-runnable config type. Various UI flows (GroupServerFragment, MainActivity, ServerActivity) updated to handle the new type.
* Initial plan
* Refactor subscription auto-update system into SubscriptionUpdater facade
Agent-Logs-Url: https://github.com/2dust/v2rayNG/sessions/63125c89-4db9-4572-8adb-10c29ea531f5
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* Add TODO comment to legacy fallback in SubscriptionUpdater
Agent-Logs-Url: https://github.com/2dust/v2rayNG/sessions/63125c89-4db9-4572-8adb-10c29ea531f5
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* Use per-subscription auto-update intervals
Migrate subscription auto-update from a global toggle/interval to per-subscription scheduling.
- Add per-subscription updateInterval (Long, default 1440 minutes) and persist in SubEdit UI; validate minimum interval (15 minutes).
- Update SubscriptionUpdater to schedule/cancel tasks per subscription, compute initial delay from subscription.lastUpdated, and skip when autoUpdate is disabled or subId is missing.
- Remove legacy global auto-update prefs and fallback logic: deleted global prefs/UI handling, MmkvManager last-attempt encode/decode, and related default setting.
- Ensure cancelling of scheduled task when removing a subscription and adjust SettingsManager initialization.
- Add localized toast strings for invalid update interval and update related layouts/resources.
This change enables individual update intervals per subscription and simplifies the updater by removing legacy global state and last-attempt persistence.
* Allow optional force-reschedule for subscriptions
Add a forceReschedule flag to SubscriptionUpdater.sync to choose the WorkManager policy (KEEP by default, REPLACE when forced). Refactor scheduleOne to accept an ExistingPeriodicWorkPolicy and use it when enqueuing periodic work; syncOne now forces REPLACE so a manual refresh recalculates next run. Remove the cancelAll helper and improve logging to include the reschedule flag/policy. This lets startup keep existing periodic work while allowing explicit reschedules when needed (e.g., after manual updates).
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
Remove echForceQuery support across the app: delete the echForceQuery fields from ProfileItem and V2rayConfig, stop mapping it in V2rayConfigManager, and remove the related UI spinner and containers in ServerActivity and layout_tls.xml. Also delete the ech_force_query_value array and all localized string entries for the ECH force query label, and adjust focus navigation to skip the removed control. This cleans up a deprecated/unused ECH force query setting.
* Add MTU and TTI settings in KCP network
* Rename ProfileItem.tti to kcpTti
Rename the ProfileItem field `tti` to `kcpTti` and update all usages accordingly. Changes update parsing/serialization in FmtBase (map query param "tti" to config.kcpTti and emit it), KCP stream settings mapping in V2rayConfigManager, UI bindings in ServerActivity, and equality checks in ProfileItem to use kcpTti. This clarifies that the field applies to KCP-specific TTI values while preserving the external query key.
Co-Authored-By: Copilot <198982749+Copilot@users.noreply.github.com>
* Add kcpMtu/kcpTti for KCP transport
Introduce kcpMtu and kcpTti properties on ProfileItem and update equality checks. Parse and emit KCP-specific mtu/tti in FmtBase (use kcpMtu/kcpTti instead of the generic mtu). Wire kcpMtu into V2rayConfigManager when building KCP stream settings and update ServerActivity to read/write the UI field to profileItem.kcpMtu/kcpTti. This separates KCP MTU/TTI from the general mtu field and removes a duplicated kcpTti entry.
Co-Authored-By: Copilot <198982749+Copilot@users.noreply.github.com>
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
* Handle unidentified package UID resolution
Add special handling for unidentified package names.
* Add method to create special unidentified app item
Added a method to create a special unidentified app item for the app picker.
* Support unidentified app UID and label
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
Allow routing rules to reference outbounds by server remarks and inject missing outbounds into the generated V2ray config. Adds BUILTIN_OUTBOUND_TAGS, a pre-pass (injectCustomOutbounds) that converts referenced non-builtin tags to outbounds, and a fallback to the proxy tag when an outbound couldn't be injected. Updates getBalance to use AppConfig.TAG_PROXY constant. Replaces the outbound-tag Spinner with an AutoCompleteTextView + dropdown button that suggests builtin tags and existing profile remarks, adds a drop-down drawable and a hint string resource.
Introduce process field for routing rules and wire it through UI, config parsing, and runtime resolution. Adds a PackageUidResolver utility to map package names to UIDs (with caching) and converts user-entered package names into UIDs when building v2ray routing rules. Updates V2rayConfig types, RoutingEditActivity layout/bindings/strings to accept process input, and adjusts getRouting to receive Context. Also adds extra logging and a defensive check in V2RayServiceManager when resolving connection owner UID.
Introduce a dynamic SOCKS port feature: add PREF_DYNAMIC_SOCKS_PORT key, settings UI checkbox and localized strings, and pref XML entry. SettingsManager now holds a runtimeSocksPort, can generate and refresh a random port (generateRandomSocksPort, refreshRuntimeSocksPort) and respects the dynamic setting when returning getSocksPort(). V2Ray service startup triggers a runtime port refresh. Settings UI disables manual SOCKS port input when dynamic mode is enabled. Minor i18n additions (QR code/title) included for several locales.
Add importantForAccessibility="no" to decorative ImageViews in check
update, bypass list, routing, subscription, user asset, and widget
layouts. Add contentDescription to QR code ImageView.
Rename and migrate Hysteria2 certificate pin field from pinSHA256 to pinnedCA256 across code and UI, and add a one-time migration at startup.
Changes:
- Added SettingsManager.migrateHysteria2PinSHA256() and call in AngApplication to copy existing profile.pinSHA256 -> profile.pinnedCA256 and clear the old field, guarded by a migration flag.
- Updated Hysteria2Fmt to read/write the query param "pinSHA256" into the new ProfileItem.pinnedCA256 field.
- Updated ProfileItem equality to compare pinnedCA256 instead of pinSHA256.
- Removed the old EditText binding and reads/writes for et_pinsha256 in ServerActivity; UI now uses et_pinned_ca256 (layout id renamed).
- Updated layout and string resources: renamed the label/id to reflect pinned_ca256 and removed legacy pinSHA256 string entries in several locale files.
This ensures existing Hysteria2 profiles keep their pin data while the code and UI use the new field name.