Skip to content

Temporarily allow a blocked tracker per app (#216)#643

Closed
kasnder wants to merge 3 commits into
masterfrom
claude/temp-unblock-216
Closed

Temporarily allow a blocked tracker per app (#216)#643
kasnder wants to merge 3 commits into
masterfrom
claude/temp-unblock-216

Conversation

@kasnder

@kasnder kasnder commented Jul 12, 2026

Copy link
Copy Markdown
Member

Implements #216: temporarily unblock a blocked tracker company/service for a single app, so a user can complete a flow that a blocked tracker breaks, without having to remember to re-block. Per the maintainer's note on the issue, this is done per-app (rather than the existing global pause via the notification).

What it does

  • In an app's tracker details list, long-pressing a BLOCKED tracker company row shows a dialog offering "Allow for 10 minutes".
  • On confirm, the company is unblocked immediately for that app and an alarm is scheduled to re-block it after 10 minutes.
  • While active, the row shows "ALLOWED FOR 10 MIN". Manually re-blocking the row (tap) ends the allowance early and cancels its alarm.

Design decisions

  • Simplicity over configurability (project philosophy): a single fixed 10-minute duration, no settings screen, no per-duration UI.
  • No reload needed for the unblock itself. The packet path reads the live TrackerBlocklist singleton per connection (ServiceSinkhole ~line 2540), so unblock() + saveSettings() take effect immediately for new connections — matching the existing per-tracker tap toggle, which also does not reload.
  • Re-block does reload defensively. When the alarm fires (or the sweep re-blocks), TempUnblockReceiver calls Rule.clearCache() + ServiceSinkhole.reload(...) to guarantee the change reaches the packet path, mirroring the header toggles.
  • Alarm mirrors WidgetAdmin's pause alarm: setAndAllowWhileIdle(RTC_WAKEUP, …), allow-while-idle so it can fire in Doze, no SCHEDULE_EXACT_ALARM permission. Inexact, so under deep Doze the re-block may lag slightly (acceptable — the fail-safe direction is re-blocking late, not never).
  • Process-death safety. Expiry timestamps are persisted in a temp_unblock SharedPreferences file. ServiceSinkhole.onCreate() calls TempUnblockReceiver.sweep(), which re-blocks anything already expired and reschedules alarms for anything still active. So a killed process cannot leave a tracker permanently unblocked.
  • New strings are English-only in values/strings.xml; translations flow via Crowdin.

Files

  • app/src/main/java/eu/faircode/netguard/TempUnblockReceiver.java (new) — allowance state, alarm scheduling, sweep, re-block.
  • TrackersListAdapter.java — long-press handler, "ALLOWED FOR 10 MIN" status, cancel-on-manual-reblock.
  • ServiceSinkhole.java — sweep on service start.
  • AndroidManifest.xml — registers the (non-exported) receiver.
  • values/strings.xml — new user-facing strings.

Needs on-device verification

  • Alarm actually fires and re-blocks under Doze (allow-while-idle timing).
  • Re-block reload reaches the packet path (a previously-allowed tracker is blocked again after 10 min without reopening the app).
  • Sweep behaviour after force-stop / reboot with an allowance pending.
  • Long-press UX on the ListView rows across supported API levels.

Note

A community contributor volunteered on the issue on 2026-07-12. This draft is a starting point — the maintainer may prefer to hand it over to that contributor or use it as a reference.

🤖 Generated with Claude Code

kasnder and others added 3 commits July 12, 2026 10:18
Long-pressing a blocked tracker company/service row in an app's tracker
details now offers "Allow for 10 minutes". The company is unblocked
immediately (the packet path reads the live TrackerBlocklist singleton),
and an AlarmManager alarm re-blocks it when the window expires, so users
never have to remember to re-block.

Design follows TC's simplicity-over-configurability philosophy: single
fixed 10-minute duration, no settings screen. The row shows "ALLOWED FOR
10 MIN" while active. Expiry timestamps are persisted so a process death
cannot leave a tracker permanently unblocked — ServiceSinkhole.onCreate
sweeps expired allowances (re-block) and reschedules alarms for active
ones. Manually re-blocking a row cancels its allowance and alarm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@kasnder kasnder left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Review finding: TempUnblockReceiver.java contained two literal NUL bytes in Java string/character literals used as the SharedPreferences key separator. NUL makes the source invalid Java input (and is not a safe XML-backed preference-key delimiter), so this prevented the new receiver from compiling. I replaced the separator with : in commit 1bbf1c1 and verified :app:compileGithubDebugJavaWithJavac succeeds.

@kasnder kasnder closed this Jul 12, 2026
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.

1 participant