Skip to content

royalgillz/Lumen

Repository files navigation

Lumen — Offline PDF Search for Android

Search every PDF on your device — instantly, privately, without the cloud.


What it does

Lumen indexes the PDFs stored on your device and lets you search their full text in milliseconds. Tap any result to open the PDF at the exact matched page with the keyword highlighted.

Search is the app, not a feature. Open Lumen, type, see results. That's it.


Privacy guarantee

Lumen has no INTERNET permission. The Android OS physically prevents it from making network requests — this is enforced at the manifest level, not just policy.

  • No accounts or sign-in
  • No file uploads
  • No analytics or crash reporting
  • No ads or tracking SDKs
  • No cloud of any kind

Your PDFs stay on your device. The search index stays on your device. Everything stays on your device.

Verify this yourself in Settings → Privacy Audit inside the app.


Features

  • Full-text search across your entire PDF library with keyword-highlighted snippets
  • Opens PDFs at the exact matched page with the search term highlighted
  • OCR support for scanned (image-based) PDFs via on-device ML Kit
  • In-viewer search with match navigation
  • Reading progress — resumes where you left off per document
  • Night mode and brightness control for the PDF viewer
  • Library management — add folders, track indexing status, see per-document errors
  • Privacy Audit screen — inspect every permission and confirm zero network access
  • Light and dark theme (Material 3)
  • Works on Android 8.0+ (API 26)

Tech stack

Concern Choice
Language Kotlin
UI Jetpack Compose + Material 3
Architecture MVVM + Repository
DI Hilt
Database Room + FTS4 (full-text search)
PDF text extraction PdfBox-Android (Apache-2.0)
PDF rendering (viewer · OCR · thumbnails) MuPDF fitz (AGPL)
OCR ML Kit Text Recognition v2 (bundled, offline)
OCR fallback Tesseract4Android
File access Storage Access Framework (SAF) — no dangerous permissions
Background indexing WorkManager
PDF viewer MuPDF fitz + custom single-canvas Android View
Preferences DataStore

Building

Requires Android Studio Ladybug (2024.2) or newer.

# Debug build
./gradlew assembleDebug

# Release bundle (for Play Store)
./gradlew bundleRelease

# Run unit tests
./gradlew test

# Run lint
./gradlew lint

Minimum SDK: API 26 (Android 8.0). Target SDK: API 35.


Architecture

app/src/main/java/com/lumen/app/
├── data/
│   ├── db/           — Room database, entities, DAOs, FTS4 query sanitizer
│   ├── pdf/          — PdfTextExtractor (PdfBox), PdfPageRenderer (bitmap for OCR)
│   ├── ocr/          — OcrEngine interface, MlKitOcrEngine, TesseractOcrEngine
│   ├── fs/           — SafRepository (SAF folder management), PdfScanner
│   └── repository/   — LibraryRepository, SearchRepository
├── domain/
│   ├── model/        — Document, SearchResult, SearchFilters
│   └── usecase/      — IndexLibraryUseCase, SearchUseCase, AddFolderUseCase
├── worker/           — IndexWorker (WorkManager foreground service)
└── ui/
    ├── theme/        — Color, Type, Theme (LumenTheme)
    ├── navigation/   — LumenNavGraph
    ├── search/       — SearchScreen, SearchViewModel
    ├── library/      — LibraryScreen, LibraryViewModel
    ├── settings/     — SettingsScreen, PrivacyAuditScreen
    ├── viewer/       — PdfViewerScreen, PdfViewerViewModel
    └── onboarding/   — OnboardingScreen, OnboardingViewModel

Data flow

  1. User picks a folder via SAF → URI persisted in DataStore with takePersistableUriPermission()
  2. IndexWorker (WorkManager) walks the tree, extracts text per page via PdfBox or OCR, writes to Room FTS4
  3. Search queries hit the FTS4 virtual table, joined with pages and documents tables
  4. Results flow as StateFlow<List<SearchResult>> debounced at 200 ms

Permissions

READ_EXTERNAL_STORAGE    — API 26–32 only; auto-removed on API 33+
FOREGROUND_SERVICE       — background indexing notification
FOREGROUND_SERVICE_DATA_SYNC
RECEIVE_BOOT_COMPLETED   — reschedule indexing after reboot
WAKE_LOCK                — keep CPU awake during indexing

INTERNET                 — intentionally absent
MANAGE_EXTERNAL_STORAGE  — intentionally absent

Contributing

Issues and pull requests are welcome. Please open an issue before starting significant work so we can discuss the approach.

  • Follow the existing code style (Kotlin, Compose, MVVM)
  • Do not add any SDK that requires network access
  • Do not add the INTERNET permission under any circumstances
  • Keep the APK size reasonable — avoid bundling large assets

Versions

Releases are tagged in git. master holds the latest released build; active development happens on the develop branch.

Version Tag Highlights
1.1 v1.1 Page-level FTS index (DB v7) with relevance ranking and grouped results, search filters (folders, OCR-only, sort, indexed date) with always-visible reset, incremental rescan, viewer zoom pill with live percentage, print and save-a-copy, notification permission flow, and release signing under the new io.github.royalgillz.lumen application ID.
1.0 v1.0 First complete build — offline FTS4 full-text search, MuPDF PDF viewer with occurrence-level in-document search and keyword highlighting, OCR highlight boxes for scanned pages, Drive-style fast-scroll thumb, device-aware viewer memory bounds, and the privacy-first Library/Settings design.

Changelog

1.1

  • Search rebuilt on a page-level FTS index (DB v7): results grouped by document with per-page hit counts, relevance ranking with filename boost, fixed AND-literal queries
  • Search filters: folder, OCR-only, sort order, and indexed-date (Any time / Today / This week / This month) with an always-visible Reset and active-filter chips
  • Incremental library rescan and smarter OCR page selection during indexing
  • Viewer: zoom pill with live percentage (tap to reset to 100%), print, save-a-copy, word selection via long-press, page snapping, accessibility announcements, highlight auto-pan and state-leak fixes
  • Bottom navigation: bold forest-green selected state; terracotta accent refinements across the app
  • Android 13+ notification permission request for indexing progress; INTERNET permission force-removed from merged manifest (ML Kit transport dependency) so the app physically cannot go online
  • Release signing config and new application ID io.github.royalgillz.lumen

1.0

  • Full-text search across indexed PDFs (filename · page · snippet)
  • PDF viewer: in-document search stepping every occurrence, amber keyword highlights, internal/external links, resume-at-last-page, brightness, scroll-mode toggle, share via overflow menu
  • Highlighting on scanned pages from OCR word boxes captured at index time
  • Fast-scroll thumb with page bubble (vertical mode)
  • Bounded viewer memory (single render gate, device-aware bitmap cache, trim-on-pressure)
  • Library: stats, Error Center for failed/encrypted files, force re-index
  • Privacy Audit screen; no INTERNET permission

License

Apache-2.0 — see LICENSE.

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages