KT

CallShield

Spam call & text blocker — GitHub-hosted spam database, Compose UI

KotlinAndroid
Delivery
Source-first
Browse code, README, and release notes on GitHub.
Primary lane
Kotlin / Android lane
The clearest adjacent context for this project inside the portfolio.
Freshness
Updated May 18, 2026
Latest release
No tag yet
README is the clearest project overview right now.

Preview

Using the generated project card as a clean fallback until a live capture is available.

CallShield card

Source at github.com/SysAdminDoc/CallShield.

README

Cached at build time, cleaned up for in-site reading, and linked back to the canonical GitHub source.

CallShield Logo

CallShield

Open-source spam call and text blocker for Android
15+ layer detection + Gradient-Boosted Tree ML | 32,933 spam numbers | Real-time caller ID | RCS filter | No required API keys

Release 32,933 Numbers 620 Tests Android 10+ MIT License No required API keys


CallShield blocks spam calls and texts using a 15+ layer on-device detection engine with a gradient-boosted tree ML scorer, campaign burst detection, RCS notification filter, and real-time caller ID overlay. Powered by a 32,933-number database with scheduled hot-list updates. Community-maintained, no accounts, no tracking.

v1.7.10 Highlights

  • Compose BOM 2026.05.00 refresh — UI dependencies now resolve on the current Compose 1.11.1 release train, with Material 3 1.4.0 and refreshed lifecycle/core/savedstate transitive locks across debug, release, and unit test configurations.
  • Configuration-aware Compose copy — snackbar, toast, semantic, validation, and search-result count text now use Compose resource APIs instead of stale LocalContext.getString / resources reads inside composables.
  • WorkManager 2.11.2 refresh — background sync, hot-list refresh, and daily digest jobs now run on the current WorkManager line with Android 15+ network-constraint fixes.
  • Worker schedule contract tests — sync, manual refresh, hot-list, and digest WorkRequests now have JVM coverage for repeat intervals, network constraints, initial delay, and retry backoff.
  • DataStore privacy hardening — settings now run on DataStore 1.2.1, and the optional AbstractAPI enrichment key is stored in a private no-backup DataStore instead of the backed-up public settings file.
  • Safer backup boundary — database and public preferences remain restorable for device transfers, while optional local credentials migrate out of Android Auto Backup scope on first read or save.
  • Reproducible-build groundwork — Gradle dependency locking is enabled, the resolved dependency graph is checked in, AGP VCS metadata is disabled for release APKs, and CI runs guards that block wall-clock build metadata from being embedded into APK inputs.
  • Release hash sidecars — release builds now produce SHA256 sidecars for APK artifact integrity, with Windows helpers for signed local releases and content-level APK rebuild comparisons.
  • Network hardening — OkHttp is upgraded to 5.3.2 and all direct data, community-report, URL-safety, and caller-ID enrichment hosts are protected by centralized certificate pinning.
  • Modern Android build stack — AGP is upgraded to 8.10.1, Kotlin/KSP are aligned on 2.2.21, and Room is upgraded to 2.8.4, keeping codegen and R8 compatible with the current Kotlin metadata used by the networking stack.
  • Stats and scan feedback polish — weekly activity labels now respect locale weekday names, Statistics detection-source labels are resource-backed, and scan permission/failure copy is consistent across call-log and SMS flows.
  • Settings credential polish — the optional AbstractAPI key is masked by default, has explicit show/hide control, reports "Not configured", "Saved locally", and "Unsaved changes" states before saving, and is now kept out of backed-up public preferences.
  • Premium-polish UX pass — tighter app chrome, restrained 12dp surface radius, zero negative type tracking, and selected navigation without pill-shaped backdrops.
  • Clearer recovery states — Blocked Log empty and filtered states now explain what happened and provide a direct "Show all activity" recovery action when filters hide records.
  • Trust-focused settings feedback — the trusted push-alert source picker now shows installed-source coverage and skeleton loading while package labels resolve.
  • Hardening foundation from v1.7.2 — spoof-proof ASCII phone normalization, SMS size caps, regex ReDoS validation, LRU notice gates, separated PendingIntent IDs, and atomic crash-log writes.
  • STIR/SHAKEN Trusted-Caller Allow — carrier PASSED attestations can short-circuit heuristic / ML blocks while still yielding to every explicit user rule.
  • 620 total JVM unit tests + GitHub Actions CI — automated test pipeline on every push.
  • Gradient-Boosted Tree ML model — 20 features, pure Kotlin, no TFLite dependency.
  • Campaign burst detection — NPA-NXX prefix clustering identifies coordinated spam waves.
  • Full accessibility — content descriptions across Compose UI, 48dp minimum touch targets.

How It Works

  1. 32,933 confirmed spam numbers — sourced from 1.75M FCC consumer complaints (2+ reports each), FTC Do Not Call, ToastedSpam, and community reports
  2. 15+ layer detection + ML — database, heuristics, campaign burst detection, on-device gradient-boosted tree, SMS content analysis, RCS filter, STIR/SHAKEN, and more
  3. Real-time caller ID overlay — parallel lookups against SkipCalls, PhoneBlock, WhoCalledMe + OpenCNAM caller name, with SIT tone anti-autodialer
  4. Scheduled hot list — trending spam numbers and campaign ranges refresh through the repository data pipeline
  5. Callback-aware — won't block callbacks from numbers you recently called, or urgent repeated callers
  6. Community-driven — one-tap anonymous contribution via Cloudflare Worker, daily merge into database

Detection Pipeline (v1.7.10)

All detection layers implement a shared IChecker interface and run in priority order via CheckerPipeline.run — first non-null result wins, every layer is testable in isolation. Priorities are stable numbers; the ladder below is the live order.

Priority Layer Verdict How It Works
10000 Manual Whitelist Allow Numbers you've explicitly marked as always-allow
9000 Contact Whitelist Allow Numbers in your phone's contacts always pass through
8500 STIR/SHAKEN Failed Block Carrier-authenticated caller ID failure gets blocked before heuristic layers
7000 User Blocklist + Database Block Personal blocklist + 32,933 confirmed spam numbers + scheduled hot-list data
6900 System Block List (A4) Block Read-only bridge to Android's BlockedNumberContract — respects stock Phone/Messages blocks
6000 Prefix Rules Block Wangiri country codes, US premium rate (+1900), international premium
5500 Wildcard / Regex Block Custom patterns like +1832555* or full regex, now with optional schedule
5400 Range Patterns (A5) Block Length-locked # patterns like +33162######, with schedule + coverage safety rail
5300 STIR/SHAKEN Trusted Allow Carrier PASSED attestations can allow through lower-confidence heuristic/ML suspicion
5000 Recently Dialed Allow Numbers you called in the last 24h — they're probably calling back
4900 Repeated Urgent Allow Same number calls 2x in 5 min → allowed through
4700 Push-Alert Bridge (A3) Allow Uber/DoorDash/Amazon/Gmail notification about an arriving call? Let it through
4500 Campaign Recorder Side-effect only; feeds burst detection below
4000 Quiet Hours Block Block all non-contact calls during configurable hours
3500 Frequency Auto-Block Block Numbers that call 3+ times in 7 days get auto-blocked
3000 Heuristic Engine Block VoIP ranges, neighbor spoofing, rapid-fire detection, 30+ rules
2500 Campaign Burst Block NPA-NXX prefix clustering detects coordinated spam waves
2000 ML Spam Scorer Block 20-feature on-device gradient-boosted tree model

SMS-specific layers (append after the shared chain): SMS Context TrustSMS Keyword Rules (with schedule) → SMS Content Analysis (30+ regex patterns, URL shorteners, suspicious TLDs, spam domain blocklist).

Additional Layers

  • Caller ID Overlay — suspicious calls (heuristic score 30-59) trigger a live multi-source lookup overlay with SkipCalls, PhoneBlock, WhoCalledMe + OpenCNAM caller name
  • RCS Filter — NotificationListenerService monitors Google/Samsung Messages for RCS spam
  • URL Safety — URLhaus (abuse.ch) checks for phishing/malware URLs in SMS/RCS (post-decision, notification only)
  • STIR/SHAKEN — blocks calls failing carrier caller ID verification (Android 11+)
  • After-Call Feedback — "Was this spam?" notification after suspicious calls for community reporting

Per-Rule Schedules (A7)

Any wildcard, range, or SMS keyword rule can be time-gated to specific days of the week and an hour window. The hour picker supports overnight wrap; daysMask = 0 is the "no gating" sentinel so rules created before v1.6 behave identically.

Live Caller ID Overlay

When a call comes in, CallShield shows a real-time overlay that queries 4 sources simultaneously:

┌──────────────────────────────────┐
│ LIKELY SPAM                      │
│ (212) 555-1234                   │
│ New York, NY                     │
│ Spam Score: 80% (17 reports)     │
│ JOHN DOE (OpenCNAM)             │
│ ⚠ SkipCalls: Flagged            │
│ ⚠ PhoneBlock: 5 reports         │
│ ⚠ WhoCalledMe: 12 reports       │
│ All sources checked              │
│ [Search] [Block] [Dismiss]       │
│ 🔈 Play SIT Tone (anti-dialer)  │
└──────────────────────────────────┘
  • Shows instantly with area code, then updates live as each source responds
  • OpenCNAM caller name lookup (free, 60 req/hr)
  • SIT Tone — ITU-T E.180 three-tone sequence tricks autodialers into removing your number
  • Color-coded: green (safe) → yellow → orange → red (spam)

ML Spam Scorer

On-device 20-feature gradient-boosted tree model — pure Kotlin, no TFLite, no heavy ML libraries. Runs in microseconds.

Feature Description
toll_free 800/888/877/etc. prefix
high_spam_npa Area code in high FTC/FCC complaint set
voip_range NPA-NXX in known VoIP spam carrier range
repeated_digits_ratio Fraction of most-common digit
sequential_asc/desc_ratio Sequential digit pairs
all_same_digit All 10 digits identical
nxx_555 Exchange is 555 (test numbers)
last4_zero Subscriber is 0000
invalid_nxx NXX starts with 0 or 1 (NANP-invalid)
subscriber_all_same Last 4 digits all same (9999)
alternating_pattern Even/odd positions uniform (5050505050)
nxx_below_200 Often unassigned ranges
low_digit_entropy Fewer than 4 distinct digits
subscriber_sequential Last 4 form ascending/descending run
+ 6 additional Campaign proximity, time-of-day, call frequency, area code density, prefix heat, neighbor spoof score

Trained weekly from the CallShield database (50K positive + 50K negative samples). Threshold: 0.7 (conservative).

Features

Number Lookup

  • Instant spam check through all 15+ detection layers with animated score gauge (0-100)
  • Auto-paste from clipboard, area code lookup (330+ US/CA), haptic feedback
  • Multi-source reverse lookup: SkipCalls + PhoneBlock + WhoCalledMe + OpenCNAM

Recent Calls & Blocked Log

  • Recent calls with contact names, risk indicators, call type icons, filter chips (All/Missed/Spam)
  • Blocked log with swipe-to-dismiss + undo, grouping with severity-scaled accent bars, filter chips
  • Staggered entrance animations, shimmer loading skeletons

Rules Management (5 tabs)

  • Blocklist, Wildcards, Keywords, Whitelist, Database
  • Export/import blocklists as JSON, per-rule enable/disable toggles
  • Regex validation before adding wildcard rules

Statistics

  • Weekly bar chart with daily breakdown
  • Detection source donut chart
  • Monthly trend line
  • Top offenders, area code heatmap, hourly heatmap

Smart Features

  • Smart suggestions — detects area code spam patterns, one-tap block entire area code
  • Weekly trend indicator — shows if spam is increasing or decreasing vs last week
  • Last blocked preview card on dashboard with tap-to-inspect
  • Blocking profiles: Work / Personal / Sleep / Maximum / Off
  • Callback detection + repeated urgent caller allow-through
  • FTC Do Not Call complaint filing
  • After-call "Was this spam?" feedback notification

Home Screen Widget

  • Today vs yesterday blocked count with trend indicator
  • Last blocked number and time
  • Quick-access to lookup and protection status

Community

  • One-tap anonymous contribution via Cloudflare Worker
  • False positive reporting subtracts votes
  • Share spam warnings to any app

Data & System

  • Full backup/restore, CSV log export, auto-cleanup (7/14/30/90 days)
  • Weekly full sync + scheduled hot list refresh, daily digest notification
  • Quick Settings tile, app shortcuts, home screen widget
  • Protection test validates all layers and permissions
  • Onboarding wizard with permission requests

Data Sources

Database (32,933 numbers, weekly CI)

Source Method
FCC Consumer Complaints Socrata API, 500K records, min 2 reports
FTC Do Not Call api.ftc.gov (DEMO_KEY)
ToastedSpam Community curated list
Community Reports Anonymous via Cloudflare Worker

Hot List (scheduled refresh)

File Contents
hot_numbers.json Top 500 trending numbers (last 24h)
hot_ranges.json NPA-NXX prefixes with 3+ active campaign numbers
spam_domains.json Phishing/spam domains from community SMS reports

Real-Time Lookup (overlay only)

Source What It Returns Auth
SkipCalls spam flag, 1M+ numbers None
PhoneBlock.net Votes, rating, blacklist None
WhoCalledMe Report count, notes None
OpenCNAM Caller name (CNAM) None (60/hr)
AbstractAPI Carrier, line type Optional key

URL Safety (post-decision)

Source What It Checks
URLhaus (abuse.ch) Phishing/malware URLs in SMS/RCS bodies

Security

  • Network security config — cleartext traffic disabled in production
  • Signing credentials — stored in local.properties, not hardcoded in build files
  • Restricted FileProvider paths — scoped to export directory only
  • Scoped backup — database and public settings are backed up for transfer/restore, while the optional AbstractAPI key is migrated to a private no-backup DataStore

Privacy

All detection runs on-device. No personal data is collected. Network requests:

  • Syncing spam database from GitHub (public)
  • Real-time lookups against free public APIs (number queried, not stored)
  • Community reports to Cloudflare Worker (phone number only, no identity)
  • URLhaus checks for SMS URL safety (URL only)

No required API keys. The optional AbstractAPI key stays on-device in no-backup storage. No accounts. No analytics. No ads.

Requirements

  • Android 10+ (API 29)
  • STIR/SHAKEN requires Android 11+ (API 30)
  • Caller ID overlay requires "Display over other apps" permission
  • RCS filter requires Notification Access permission

Building

./gradlew verifyReproducibleBuildInputs verifyReleaseApkReproducibleMetadata

Requires JDK 17+. Signed APK at app/build/outputs/apk/release/app-release.apk. Generate the release hash sidecar with:

.\scripts\write-release-sha256.ps1

See docs/reproducible-builds.md for the dependency-lock and hash-comparison runbook.

F-Droid submission prep lives in fastlane/metadata/android/en-US/, docs/fdroid/com.sysadmindoc.callshield.yml, and docs/fdroid-submission.md. The actual F-Droid merge request and signature-copy verification still require an fdroiddata/GitLab environment.

Signing: Create local.properties in the project root with your keystore credentials:

RELEASE_STORE_FILE=path/to/keystore.jks
RELEASE_STORE_PASSWORD=...
RELEASE_KEY_ALIAS=...
RELEASE_KEY_PASSWORD=...

Testing

./gradlew testDebugUnitTest   # 620 tests

CI runs automatically via GitHub Actions on every push and pull request.

Tech Stack

Component Technology
Language Kotlin 2.2.21
UI Jetpack Compose BOM 2026.05.00 + Material 3
Theme Premium AMOLED black + Catppuccin Mocha
Database Room 2.8.4 (SQLite) — 6 entities
Networking OkHttp 5.3.2 + certificate pinning
JSON Moshi
ML Pure Kotlin gradient-boosted tree (20 features)
Settings DataStore Preferences 1.2.1
Background WorkManager 2.11.2
Community API Cloudflare Workers
URL Safety URLhaus (abuse.ch)
CI GitHub Actions
Tests 620 JVM unit tests (JUnit)
Strings 955+ resources and 6 plural groups (translation-ready)
Accessibility 100+ content descriptions, 48dp touch targets
Min SDK 29 (Android 10)
Target SDK 36

For deep technical details, see CLAUDE.md.

License

MIT

Read on GitHub → github.com/SysAdminDoc/CallShield