Skip to content

Fix Android 11 notification action not clickable#793

Open
Pawloland wants to merge 2 commits into
tailscale:mainfrom
Pawloland:notification_fix
Open

Fix Android 11 notification action not clickable#793
Pawloland wants to merge 2 commits into
tailscale:mainfrom
Pawloland:notification_fix

Conversation

@Pawloland

Copy link
Copy Markdown
Contributor

Fix expedited WorkRequests by implementing getForegroundInfo() method for all Workers, thus fixing intent handling on Android 11 and older.

Fixes tailscale/tailscale#19772

… for all Workers, thus fixing intent handling on Android 11 and older

Fixes tailscale/tailscale#19772

Signed-off-by: Pawloland <59684145+Pawloland@users.noreply.github.com>
@Pawloland

Copy link
Copy Markdown
Contributor Author

I tested the intents with bellow adb commands. It works as expected on Android 11 now. I also added guards inside, so workers are triggered only when the actual state changes. Otherwise the temporary notification which is always sent by the system on older Androids, when expedited worker request is run, would replace the normal status notification, the one with the connect/disconnect button. Since the state would not change, the rerender of the default notification would not be triggered, but the temporary one would be, and it would be shown until the VPN is connected again, triggering the change in prefs and rerender of the default notification. This fixed the issue which made it apparent to me - non clickable connect/disconnect button in the notification, but it fundamentally fixes intent handling on older APIs, so 3rd party apps integrations on those.

#enable VPN
adb shell am broadcast -a com.tailscale.ipn.CONNECT_VPN -n com.tailscale.ipn/com.tailscale.ipn.IPNReceiver

#disable VPN
adb shell am broadcast -a com.tailscale.ipn.DISCONNECT_VPN -n com.tailscale.ipn/com.tailscale.ipn.IPNReceiver

#configure exit node 
adb shell am broadcast -a com.tailscale.ipn.USE_EXIT_NODE -n com.tailscale.ipn/com.tailscale.ipn.IPNReceiver --es exitNode "my-exit-node" --ez allowLanAccess true

#reset exit node configuration
adb shell am broadcast -a com.tailscale.ipn.USE_EXIT_NODE -n com.tailscale.ipn/com.tailscale.ipn.IPNReceiver

…smissible on Android 11 and older when triggering USE_EXIT_NODE intent

Signed-off-by: Pawloland <59684145+Pawloland@users.noreply.github.com>
@Pawloland

Copy link
Copy Markdown
Contributor Author

@kari-ts Should be ready to merge. The second commit also fixed the bellow warnings:

W Verification of void com.tailscale.ipn.UseExitNodeWorker.<clinit>() took 111.383ms (80.80 bytecodes/s) (1528B approximate peak alloc) 
W Verification of java.lang.Object com.tailscale.ipn.UseExitNodeWorker.doWork$runAndGetResult(com.tailscale.ipn.UseExitNodeWorker, com.tailscale.ipn.UninitializedApp, kotlin.coroutines.Continuation) took 254.280ms (1604.53 bytecodes/s) (12192B approximate peak alloc) 
W Verification of java.lang.Object com.tailscale.ipn.UseExitNodeWorker.doWork(kotlin.coroutines.Continuation) took 142.068ms (1520.39 bytecodes/s) (5328B approximate peak alloc) 
I Work [ id=ee6ab7b1-13b2-47fd-a3f5-63ee7e740853, tags={ com.tailscale.ipn.UseExitNodeWorker, ipn-use-exit-node } ] was cancelled java.util.concurrent.CancellationException:
 Task was cancelled. at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1183)
         at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:513)
         at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:474)
         at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:316)
         at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
         at java.lang.Thread.run(Thread.java:923)

@Pawloland

Copy link
Copy Markdown
Contributor Author

@kari-ts I hate to be that guy, but is there any hope of merging it?

@Pawloland

Copy link
Copy Markdown
Contributor Author

@barnstar, can it be merged?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses Android 11 and older behavior for expedited WorkRequests triggered by notification actions by adding getForegroundInfo() implementations to the Workers involved, so WorkManager can run them as foreground work without throwing and breaking intent handling.

Changes:

  • Add getForegroundInfo() to StartVPNWorker, StopVPNWorker, and UseExitNodeWorker with minimal “status” notifications.
  • Add new string resources for “Starting…”, “Stopping…”, and “Changing exit node…” notification titles (and update the About footer year).
  • Add receiver-side short-circuiting to avoid enqueuing work that would overwrite the status notification when the requested state appears unchanged.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
android/src/main/res/values/strings.xml Adds notification-title strings used for Worker foreground notifications; minor formatting/year update.
android/src/main/java/com/tailscale/ipn/UseExitNodeWorker.kt Refactors exit-node preference update flow and adds getForegroundInfo() for expedited work compatibility.
android/src/main/java/com/tailscale/ipn/StopVPNWorker.java Adds getForegroundInfo() so expedited stop work can run on Android 11 and older.
android/src/main/java/com/tailscale/ipn/StartVPNWorker.java Adds getForegroundInfo() so expedited start work can run on Android 11 and older.
android/src/main/java/com/tailscale/ipn/IPNReceiver.java Adds “skip enqueuing” checks for disconnect/exit-node actions to reduce notification churn.

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

Comment on lines +32 to +44
if (!app.isAbleToStartVPN()) {
return Result.failure(
Data.Builder().putString(
ERROR_KEY, app.getString(R.string.vpn_is_not_ready_to_start)
).build()
)
}

val netmap = Notifier.netmap.value ?: return Result.failure(
Data.Builder().putString(
ERROR_KEY, app.getString(R.string.tailscale_is_not_setup)
).build()
)
Comment thread android/src/main/java/com/tailscale/ipn/IPNReceiver.java
Comment thread android/src/main/java/com/tailscale/ipn/IPNReceiver.java
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.

Android 11 notification action not clickable

2 participants