feat: add ad/tracker blocker with auto-updating filter list - #101
feat: add ad/tracker blocker with auto-updating filter list#101joshi-7373 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a built-in ad/tracker blocking feature (including cosmetic filtering and YouTube ad skipping) with user-facing settings and an auto-updating remote filter list.
Changes:
- Introduces
AdBlocker(host blocking + JS injections) andFilterListUpdater(weekly AdGuard list fetch + caching). - Integrates blocking into
ConfiguredWebViewrequest interception andonPageFinishedscript injection. - Adds Settings UI + preference storage + documentation updates for the new blocker.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| app/src/main/res/values/strings.xml | Adds new Settings strings for Privacy/Ads and ad-block descriptions. |
| app/src/main/java/com/kododake/aabrowser/web/FilterListUpdater.kt | New remote filter list downloader/cacher (AdGuard) with rate limiting. |
| app/src/main/java/com/kododake/aabrowser/web/ConfiguredWebView.kt | Hooks the blocker into WebView request interception and JS injection. |
| app/src/main/java/com/kododake/aabrowser/web/AdBlocker.kt | New ad/tracker blocking engine + cosmetic and YouTube JS. |
| app/src/main/java/com/kododake/aabrowser/settings/SettingsViews.kt | Adds a Settings section + toggle to enable/disable ad blocking. |
| app/src/main/java/com/kododake/aabrowser/data/BrowserPreferences.kt | Persists the ad-block enabled preference. |
| app/src/main/assets/adblock_hosts.txt | Adds a bundled host list asset to extend the core list. |
| README.md | Documents the new ad blocking feature and update behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Thanks for the review! I've addressed the findings in the latest commit: Validation mutating the live blocklist before commit — fixed. Downloads are now parsed into a temporary set (
Duplicate On the Note: these changes are self-reviewed but have not yet been validated on a physical Android Auto head unit. |
Add a built-in ad and tracker blocker for the in-app WebView: - Network-level blocking via WebViewClient.shouldInterceptRequest using a merged blocklist: a hard-coded core list, a bundled hosts asset, and an auto-updating AdGuard DNS filter that refreshes weekly in the background. - Conservative cosmetic CSS to hide leftover empty ad containers. - YouTube ad handling: auto-skips skippable ads and fast-forwards un-skippable ones, restoring the user's mute state so real videos are never left muted, and only ever acting on the player's own video element. - New 'Privacy & Ads' toggle in Settings (enabled by default). - Robust updater: atomic cache writes, size cap, and graceful fallback to the bundled lists if a download fails. Note: server-stitched (SSAI) YouTube ads cannot be removed inside a WebView.
- Validate downloaded filter lists into a temporary set and only merge hosts into the live blocklist after the cache is committed, so a failed commit can no longer leave half-applied hosts in memory. - Gate the remote filter-list download behind the enabled flag so no network fetch happens while the blocker is off (matches the README), and refresh on enable. - Remove an invalid host entry (yandex.ru/metrika contained a path) and a duplicate (districtm.io) from the bundled list.
37265d5 to
cad0405
Compare
There was a problem hiding this comment.
Thank you for the PR. Introducing a native ad and tracker blocker significantly improves the browser's capabilities. The implementation is lightweight, but there are a few important points regarding thread-safety, resource management, and reliability that should be addressed before merging.
-
Thread-Safety Concerns on Filter List Updates
Although the list is merged into the live blocker (AdBlocker.addHosts(...)) only after successfully committing the cache file to avoid memory corruption, the operation still happens on a background thread. SinceshouldInterceptRequestreads from this blocklist on the WebView's I/O thread, please ensure the underlying collections/structures inAdBlockerare thread-safe (e.g. usingConcurrentHashMap.newKeySet()) to preventConcurrentModificationExceptionduring concurrent reads and writes. -
Resource Leak: Potential Temporary File Leak on I/O Exception
InFilterListUpdater.kt, if anIOExceptionoccurs during the execution ofresponse.body.byteStream().useortmp.outputStream().use, the execution will halt and jump to the caller's catch block, leaving the incompleteadblock_remote.tmpfile on the disk.
- Fix: Wrap the download and parsing logic in a
try-finallyblock to guarantee that the temporary file is deleted:val tmp = File(context.filesDir, TMP_FILE_NAME) try { // download and parse logic... } finally { if (tmp.exists()) { tmp.delete() } }
- Background Thread and Lifecycle Management
Starting a raw daemon thread viaThread { ... }.start()for network operations is discouraged in modern Android development. It ignores the system's power-saving states (Doze mode, App Standby) and has no lifecycle awareness (e.g., cancelling if the app is closed).
- Fix: Consider refactoring this to use Android's
WorkManageror Kotlin Coroutines with a network constraint (e.g., requiring network connectivity) to ensure efficient and system-friendly background scheduling.
- Fragility of YouTube Ad-Skipping Selectors
The selectors used inAdBlocker.YOUTUBE_AD_SKIP_JSto fast-forward ads and auto-click skip buttons are highly dependent on YouTube's DOM structure. Since YouTube changes its DOM frequently, please ensure:
- The injection script is strictly scoped to YouTube domains (verify that
AdBlocker.isYouTube(url)uses exact domain matching to prevent injection on unrelated domains). - The script has robust error handling to prevent accidental fast-forwarding or permanent muting of actual user videos if selectors fail.
- Broken Link:
FILTER_URLReturns HTTP 404
InFilterListUpdater.kt, the definedFILTER_URL(https://raw.githubusercontent.com/AdguardTeam/AdGuardSDNSFilter/master/Filters/filter.txt) returns an HTTP 404 error (Not Found). This causes the weekly automatic filter list update to always fail.
- Fix: Update the URL to a valid and active filter list location (e.g., checking if the repository path or branch name has changed, or using an official hosted mirror).
Please review these points and update the PR accordingly.
Summary
Adds a built-in ad & tracker blocker to the in-app WebView — network blocking, cosmetic ad-hiding, and YouTube video-ad skipping. It is enabled by default and can be toggled under Settings → Privacy & Ads. The blocklist updates itself automatically from a public AdGuard list, so it needs no manual upkeep.
Why
Ad blocking is listed as a known gap in the README ("No Ad Blocking — contributions welcome"). This implements it natively and keeps the blocklist current on its own.
What changed
New files
web/AdBlocker.kt— blocking engine, blocklist parser, cosmetic CSS, and the YouTube ad-skip script.web/FilterListUpdater.kt— weekly background download and caching of the AdGuard DNS filter.assets/adblock_hosts.txt— bundled fallback blocklist.Modified
web/ConfiguredWebView.kt— blocks requests in shouldInterceptRequest and injects the cosmetic + YouTube scripts in onPageFinished.settings/SettingsViews.kt— adds the "Privacy & Ads" toggle.data/BrowserPreferences.kt— persists the enabled preference.res/values/strings.xml— new setting strings.README.md— features, current issues, and a privacy note.How it works
Network blocking — drops requests to known ad/tracker hosts (subdomain-aware) plus a few ad URL paths, returning an empty 204. The blocklist merges a hard-coded core list, the bundled asset, and the auto-updating AdGuard list. The parser reads both hosts format and AdGuard domain rules, safely skipping exceptions, cosmetic, and modifier rules.
Cosmetic CSS — conservative selectors hide leftover empty ad boxes.
YouTube — auto-clicks Skip, fast-forwards un-skippable ads, and removes banner/overlay ads. It acts only when YouTube flags the player as showing an ad, targets the player's own video element, and saves/restores the mute state so real videos are never left muted.
Limitations
Server-stitched (SSAI) YouTube ads cannot be removed inside a WebView, and the YouTube skip selectors may need occasional updates as YouTube changes.
Notes
No new permissions or dependencies (reuses OkHttp and the existing INTERNET permission). Self-reviewed against the codebase; not yet validated on a physical Android Auto head unit — feedback on real-device behaviour is welcome.