Skip to content

fix(android): keep selected server across VPN consent dialog#8905

Open
garmr-ulfr wants to merge 3 commits into
mainfrom
fix/android-vpn-consent-drops-server-tag
Open

fix(android): keep selected server across VPN consent dialog#8905
garmr-ulfr wants to merge 3 commits into
mainfrom
fix/android-vpn-consent-drops-server-tag

Conversation

@garmr-ulfr

@garmr-ulfr garmr-ulfr commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Problem

On the first connect of a session, tapping a specific server routes the tunnel to the nearest exit instead. In MainActivity, connectToServer(tag) bails at the isVPNServiceReady() check that shows the OS VPN-consent dialog and discards the tag. onActivityResult then resumes unconditionally with startVPN() (auto-select), so the tunnel connects to the nearest server while the UI still shows the tapped one.

Fix

  • Record the pending selection (pendingTag) when the consent dialog interrupts the connect.
  • After consent, resumePendingConnect() replays it via the tag-preserving connectToServer() path instead of falling back to auto.
  • connectToServer owns the pendingTag lifecycle: set only when deferring for consent, cleared only after a successful dispatch — so a failed service start preserves the selection for retry.
  • Both permission callbacks (onActivityResult, onRequestPermissionsResult) route through resumePendingConnect().

The service side already handled ACTION_CONNECT_TO_SERVER correctly; the bug was entirely MainActivity dropping the tag across the consent round-trip.

Summary by CodeRabbit

  • Bug Fixes
    • Preserved the user-selected VPN server when the connection flow was interrupted by VPN consent/permissions.
    • After permissions were granted, the app now continues the intended connection instead of falling back to automatic server selection.
    • Improved behavior when switching VPN servers while a connection is already active, ensuring the correct server is selected and connected.

On the first connect of a session, connectToServer(tag) bailed at the
isVPNServiceReady() check that shows the OS VPN-consent dialog and
discarded the tag. onActivityResult then resumed unconditionally with
startVPN() (auto-select), so the tunnel connected to the nearest exit
while the UI still showed the tapped server.

Record the pending selection when the consent dialog interrupts the
connect and replay it after consent via resumePendingConnect(), which
dispatches to the tag-preserving connectToServer() path instead of
auto. connectToServer owns the pendingTag lifecycle: it is set only
when deferring for consent and cleared only after a successful
dispatch, so a failed start preserves the selection for retry. Both
permission callbacks now route through resumePendingConnect.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a93bcf4d-b85e-43e5-af87-c0e36e9e66af

📥 Commits

Reviewing files that changed from the base of the PR and between 4e987e8 and 636ece9.

📒 Files selected for processing (1)
  • android/app/src/main/kotlin/org/getlantern/lantern/MainActivity.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • android/app/src/main/kotlin/org/getlantern/lantern/MainActivity.kt

📝 Walkthrough

Walkthrough

MainActivity now preserves the selected VPN server tag through interrupted VPN or notification permission flows and resumes the tagged connection after consent succeeds.

Changes

VPN server selection persistence

Layer / File(s) Summary
Pending server tag state
android/app/src/main/kotlin/org/getlantern/lantern/MainActivity.kt
Adds volatile pending-tag tracking, records tags when VPN preparation requires consent, and clears the tag for automatic or successfully dispatched connections.
Resume interrupted connection
android/app/src/main/kotlin/org/getlantern/lantern/MainActivity.kt
Adds resumePendingConnect() and uses it after VPN and notification permission success callbacks to restore the selected tag or start automatic selection.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main Android fix: preserving the selected server through the VPN consent flow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/android-vpn-consent-drops-server-tag

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes an Android first-connect behavior where a user-selected server tag was lost when the OS VPN-consent dialog interrupted the flow, causing the tunnel to connect via auto-select while the UI still reflected the tapped server.

Changes:

  • Introduces a pendingTag field to persist the selected server tag across the VPN-consent round trip.
  • Adds resumePendingConnect() to replay the deferred connect (tagged connect vs auto connect) after permission callbacks.
  • Routes both onActivityResult (VPN consent) and onRequestPermissionsResult through resumePendingConnect().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread android/app/src/main/kotlin/org/getlantern/lantern/MainActivity.kt Outdated
connectToServer/startVPN run on MethodHandler's Dispatchers.IO
coroutine, while pendingTag is read on the main thread in the
permission callbacks. As a plain var there is no happens-before
guarantee, so a stale read after consent could fall back to
auto-select. Volatile gives the needed visibility; accesses are
single-variable so no atomicity is required.
@garmr-ulfr garmr-ulfr marked this pull request as ready for review July 9, 2026 22:44
@garmr-ulfr garmr-ulfr requested review from atavism and jigar-f July 9, 2026 22:45

@jigar-f jigar-f left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants