Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions OPEN_ISSUES_TRIAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@
**Generated:** 2026-07-11 · **Reviewed against:** `CLAUDE.md` design philosophy + `TODO.md` standing constraints
**Method:** Every item below was traced into the actual code (Java + native C + Rust gotatun). Line numbers are from the tree at/around `master` (`a9f060a`) — re-verify before editing, code moves.

## Status (live)

Draft PRs are being generated by agents. This table is the running checklist — ✅ = draft PR open.

| WI | Issue(s) | State | PR |
|----|----------|-------|----|
| WI-1 | #327 pause auto-resume | ✅ draft PR open | [#601](https://github.com/TrackerControl/tracker-control-android/pull/601) |
| WI-2 | #576 dead toggle | ✅ draft PR open | [#602](https://github.com/TrackerControl/tracker-control-android/pull/602) |
| WI-3 | #478 PMTUD MSS clamp | 🚧 in progress | — |
| WI-4 | #339 IPv6 DNS | 🚧 in progress | — |
| WI-5 | #526/#331 self-disable | 🚧 in progress | — |
| WI-6 | #554/#561/#358 transparency | 🚧 in progress | — |
| WI-7+8 | #586/#575/#551/#560/#559 UI polish | 🚧 in progress | — |
| WI-9 | #405 memory footprint | 🚧 in progress | — |
| WI-11 | general self-check / diagnostics (new) | 🚧 investigate + draft | — |

## How to use this document

Each **work item (WI-n)** in Sections A/B is self-contained: one agent can be handed a single WI and act on it without re-reading the whole review. Each carries a **Verdict**, the **root cause with file:line**, a **concrete fix**, and a **risk/scope** note.
Expand All @@ -20,16 +36,18 @@ Verdict vocabulary:

## Section A — Ready-to-implement fixes (Fixable-aligned)

### WI-1 · Pause auto-resumes after a manual resume, dropping connections
### WI-1 · Pause auto-resumes after a manual resume, dropping connections — ✅ Draft PR [#601](https://github.com/TrackerControl/tracker-control-android/pull/601)
- **Issue:** [#327](https://github.com/TrackerControl/tracker-control-android/issues/327)
- **Status:** Draft PR #601 open. Fix in `ActivityMain.onActivityResult` (REQUEST_VPN branch): cancel the `INTENT_ON` pause alarm before `ServiceSinkhole.start(...)`, matching `WidgetAdmin`'s PendingIntent (the Quick-Settings tile `ServiceTileMain` already did this — confirms the main-UI path was the gap). `compileGithubDebugJavaWithJavac` green. Needs on-device pause→resume verification.
- **Verdict:** Fixable-aligned. Smallest clean win on the board; no packet-path risk.
- **Symptom:** User pauses TC for 10 min from the notification, then manually resumes from the app. Later the original pause timer still fires — TC vibrates, a second foreground/VPN re-init happens mid-session, and in-flight connections drop (one reporter lost a payment).
- **Root cause:** A pause schedules an `INTENT_ON` alarm `pause` minutes out in `WidgetAdmin.java:84-90`. That alarm is only cancelled inside `WidgetAdmin.onReceive` for its three broadcast actions (`WidgetAdmin.java:57-61`). The **main-UI resume path does not go through that code** — `ActivityMain.java:282-355` sets `enabled=true` and calls `ServiceSinkhole.start(...)` directly, never calling `am.cancel(...)`. The orphaned alarm survives and re-fires.
- **Fix:** In the UI resume path (`ActivityMain`), cancel the pending `INTENT_ON` pause alarm (mirror the cancel in `WidgetAdmin.java:57-61`), or make the alarm handler a no-op when TC is already enabled (idempotent resume).
- **Risk/scope:** Tiny, UI/lifecycle only. No native or DNS change.

### WI-2 · Some tracker domains silently won't toggle ALLOWED→BLOCKED (regression in 2026.04.03)
### WI-2 · Some tracker domains silently won't toggle ALLOWED→BLOCKED (regression in 2026.04.03) — ✅ Draft PR [#602](https://github.com/TrackerControl/tracker-control-android/pull/602)
- **Issue:** [#576](https://github.com/TrackerControl/tracker-control-android/issues/576) (confirmed by 3+ users: Android 11 rooted, Android 16, F-Droid)
- **Status:** Draft PR #602 open. UI-only fix in `TrackersListAdapter`: override `isEnabled(position)`/`areAllItemsEnabled()` so ambiguous shared-IP rows are non-interactive at the ListView level (standard idiom), plus a defensive no-op guard + informative toast, and a new `allowed_shared_ip` string ("Allowed — shared IP; enable Strict mode to block"). Runtime blocking semantics untouched. `compileGithubDebugJavaWithJavac` green. Needs visual confirmation.
- **Verdict:** Fixable-with-tension leaning aligned — the **runtime** behaviour is correct-by-design; the **UI** lies to the user. Fix the UI, not the blocking logic.
- **Symptom:** In an app's tracker list (Standard mode), tapping certain domains (e.g. an Amazon ad domain under gasbuddy) does nothing — the row won't flip to BLOCKED — while other rows in the same enabled section toggle fine.
- **Root cause:** The per-row status is recomputed in `TrackersListAdapter.java:305-318`. For domains where `t.isAllowedInStandardMode()` is true, it force-pins the label back to ALLOWED in non-strict mode:
Expand Down Expand Up @@ -118,6 +136,14 @@ Verdict vocabulary:
- **Analysis:** No literal ~2.5 min timer exists anywhere. Two *continuous* CPU loops were added by the gotatun migration and run **only when remote egress is enabled**: gotatun's 250 ms `handle_timers` tokio loop (`gotatun-0.7.2 device/mod.rs:500-502`, spawned at `:219`) and TC's 1 s `WgConnectivityMonitor` poll calling `tunnel.stats()` over JNI (`WgConnectivityMonitor.kt:226`, `LOOP_SLEEP_MS=1000`). The ~2.5 min *radio* cadence is emergent WG re-handshake (gotatun `noise/timers.rs:30-31`, `REKEY_AFTER_TIME=120s`/`REJECT_AFTER_TIME=180s`) because screen-off drops persistent-keepalive (`WgConfig.kt:31-35`) — this is protocol-optimal and intentionally not "fixed" with a keepalive (would add its own wakeups). The restart-backoff defeat noted historically is **already fixed** (`restartAttempts` now resets on observed rx, `WgEgress.kt` `onRxAdvanced`).
- **Fix:** When the tunnel is idle **and** screen-off, back off the 1 s `WgConnectivityMonitor` poll (extend its existing `onSuspended`/doze handling to e.g. 10–30 s) and consider a slower/adaptive gotatun tick. No change for default (no-egress) users — they have no such loop.

### WI-11 · General self-check / diagnostics (strategic — addresses the un-triageable-report problem)
- **Motivation:** "Apps don't connect" / "battery drain" reports are un-actionable because reporters never provide the deciding fact (Private DNS/DoT on? always-on VPN? blocking mode? remote egress? IPv6-only carrier?). Rather than chase each report, give the app an **on-demand self-check** that captures those facts itself and produces a plain-language verdict + shareable report.
- **Verdict:** Fixable-aligned (diagnostic, not configuration — fits the philosophy). Report-first core is low-risk (no packet-path, no background pollers).
- **Design constraints (maintainer steer):** Battery is *surfaced, not re-investigated* — surface TC's own wakelock/CPU/wakeup stats + the mis-attribution explanation (see C-1); do not re-derive. Connectivity diagnostics stay in the **non-WireGuard** path (the gotatun egress is already well-worked). On-demand only (battery). All data on-device; user chooses to share.
- **Heritage note:** NetGuard originally had diagnostic/network-info/log-export code; the maintainer believes it was **removed** from TC and is unsure it was ever sufficient for TC's DNS/tracker model. First step is git-history archaeology to recover it and assess the gap.
- **Signals the TC check must surface** (from Sections B/C + the connectivity map): Private DNS/DoT active (#348), IPv6-only DNS discarded (#339), always-on/onRevoke state (#526/#331), blocking mode + Strict shared-IP overblock (#297), system-apps/DoH/remote-egress toggles, tun-up / DNS-resolving / route sanity, and the battery attribution stats.
- **Status:** 🚧 Opus agent investigating + drafting PR (report-first core; active health-check/auto-recovery deferred as documented follow-up).

---

## Section C — Unfixable-by-construction (respond to reporter; do NOT add a knob)
Expand Down
20 changes: 14 additions & 6 deletions app/src/main/java/eu/faircode/netguard/AdapterLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,24 +169,32 @@ public void bindView(final View view, final Context context, final Cursor cursor
tvTime.setText(new SimpleDateFormat("HH:mm:ss").format(time));

// Show connection type
if (connection <= 0)
String connectionDescription;
if (connection <= 0) {
ivConnection.setImageResource(allowed > 0 ? R.drawable.host_allowed : R.drawable.host_blocked);
else {
connectionDescription = context.getString(allowed > 0 ? R.string.log_connection_allowed : R.string.log_connection_blocked);
} else {
String networkType = context.getString(connection == 1 ? R.string.log_connection_wifi : R.string.log_connection_other);
String allowedState = context.getString(allowed > 0 ? R.string.log_connection_allowed : R.string.log_connection_blocked);
connectionDescription = networkType + ", " + allowedState;
if (allowed > 0)
ivConnection.setImageResource(connection == 1 ? R.drawable.wifi_on : R.drawable.other_on);
else
ivConnection.setImageResource(connection == 1 ? R.drawable.wifi_off : R.drawable.other_off);
}
ivConnection.setContentDescription(connectionDescription);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Drawable wrap = DrawableCompat.wrap(ivConnection.getDrawable());
DrawableCompat.setTint(wrap, allowed > 0 ? colorOn : colorOff);
}

// Show if screen on
if (interactive <= 0)
if (interactive <= 0) {
ivInteractive.setImageDrawable(null);
else {
ivInteractive.setContentDescription(null);
} else {
ivInteractive.setImageResource(R.drawable.screen_on);
ivInteractive.setContentDescription(context.getString(R.string.log_screen_on));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Drawable wrap = DrawableCompat.wrap(ivInteractive.getDrawable());
DrawableCompat.setTint(wrap, colorOn);
Expand Down Expand Up @@ -233,9 +241,9 @@ public void bindView(final View view, final Context context, final Cursor cursor
} catch (PackageManager.NameNotFoundException ignored) {
}

if (info == null)
if (info == null) {
ivIcon.setImageDrawable(null);
else {
} else {
if (info.icon <= 0)
ivIcon.setImageResource(android.R.drawable.sym_def_app_icon);
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.textError.setVisibility(View.VISIBLE);
}

holder.switchEnabled.setContentDescription(
context.getString(R.string.blocklist_enable_description, item.url));
holder.switchEnabled.setChecked(item.enabled);
holder.switchEnabled.setOnCheckedChangeListener((buttonView, isChecked) -> {
item.enabled = isChecked;
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/about.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@drawable/ic_rocket_colour" />

<LinearLayout
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/actionmain.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/switch_tracker_control_description"
android:saveEnabled="false" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/android.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@drawable/ic_rocket_colour" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/datasaving.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@drawable/ic_rocket_colour" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/doze.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@drawable/ic_rocket_colour" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/enable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@drawable/ic_rocket_colour" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/forwardadd.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@mipmap/ic_launcher_round" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/forwardapproval.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@mipmap/ic_launcher_round" />

<TextView
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/res/layout/fragment_actions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:accessibilityHeading="true"
android:gravity="bottom"
android:minHeight="24dp"
android:text="@string/personalised_ads"
Expand Down Expand Up @@ -64,6 +65,7 @@
android:id="@+id/img"
android:layout_width="@dimen/card_img"
android:layout_height="@dimen/card_img"
android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
Expand Down Expand Up @@ -102,6 +104,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:accessibilityHeading="true"
android:gravity="bottom"
android:minHeight="24dp"
android:text="@string/data_managment"
Expand Down Expand Up @@ -135,6 +138,7 @@
android:id="@+id/img2"
android:layout_width="@dimen/card_img"
android:layout_height="@dimen/card_img"
android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
Expand Down Expand Up @@ -194,6 +198,7 @@
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:accessibilityHeading="true"
android:gravity="bottom"
android:minHeight="24dp"
android:text="@string/contacts"
Expand Down Expand Up @@ -228,6 +233,7 @@
android:id="@+id/img3"
android:layout_width="@dimen/card_img"
android:layout_height="@dimen/card_img"
android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
Expand Down Expand Up @@ -295,6 +301,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:accessibilityHeading="true"
android:gravity="bottom"
android:minHeight="24dp"
android:text="@string/block_tracking"
Expand Down Expand Up @@ -328,6 +335,7 @@
android:id="@+id/img4"
android:layout_width="@dimen/card_img"
android:layout_height="@dimen/card_img"
android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/layout/item_blocklist.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/blocklist_delete_description"
android:minWidth="48dp"
android:minHeight="48dp"
android:src="@android:drawable/ic_menu_delete" />

</LinearLayout>
5 changes: 3 additions & 2 deletions app/src/main/res/layout/item_insights_header.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@

<ImageButton
android:id="@+id/btnShare"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="4dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/insights_share"
android:padding="6dp"
android:src="@drawable/ic_ios_share"
app:tint="@android:color/white" />

Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/item_timeline_entry.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="12dp"
android:importantForAccessibility="no"
tools:src="@android:drawable/sym_def_app_icon" />

<TextView
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/layout/item_vpn_status.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/vpnEnabledSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
android:contentDescription="@string/vpn_enabled_switch_description" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
1 change: 1 addition & 0 deletions app/src/main/res/layout/list_item_trackers.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
android:id="@+id/root_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:accessibilityHeading="true"
android:text="@string/tracker_name"
android:textColor="?android:textColorPrimary"
android:textSize="24sp"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/log.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

<ImageView
android:id="@+id/ivIcon"
android:importantForAccessibility="no"
android:layout_width="24dip"
android:layout_height="24dip"
android:layout_gravity="center_vertical" />
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/sure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@drawable/ic_rocket_colour" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/troubleshooting.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@drawable/ic_rocket_colour" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/vpn.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
android:src="@mipmap/ic_launcher_round" />

<TextView
Expand Down
Loading