A no-frills Android document scanner. Open the app, tap Scan, point your phone at the page, share the result as a PDF (or JPEG / PNG). No ads, no sign-in, no cloud upload, no "premium" tier.
The actual scanning — edge detection on creased and folded paper, perspective correction, multi-page batching — is handled by Google's on-device ML Kit document scanner, so the magic is the same one Google Drive uses. This app is just a thin wrapper around it: launch the scanner, save the result, share.
- Capture single or multi-page scans (up to 50 pages per document)
- Automatic edge detection and perspective correction
- Import existing photos from the gallery instead of capturing live
- Share each scan as PDF, JPEG, or PNG via the standard Android share sheet (Gmail, Drive, Messages, AirDrop-equivalents, anything) — with real thumbnails of the scan in the chooser preview
- Quick-send presets — register tiles like "Email to dad" or "Send to WhatsApp" that skip the OS chooser and pre-fill recipients
- Rename any scan — the new name is what Gmail, Drive etc. see as the attached file's name
- OCR text search — extracted text from every page is indexed, so the search bar finds scans by their content even if you never renamed them
- Auto-suggested names from OCR — the rename dialog offers the first meaningful line on page 1 as a one-tap suggestion
- Star scans to pin them to the top of the list
- Tap a row for a full-screen preview with pinch-to-zoom + horizontal swipe through every page
- Edit pages within a scan — reorder, delete a page, or append new ones
- Long-press a row to enter selection mode and bulk-delete several scans
- Settings: choose between the full ML Kit editor and a one-snap quick capture, set a default share format
- Backup to any folder via Android's Storage Access Framework — works with Google Drive, Dropbox, OneDrive, local storage, USB; the user picks once, the app mirrors scans there
- Thumbnails of the first page on every row
- Scans persist between launches on local storage
- Adaptive launcher icon, branded splash, light + dark mode
- Folders / tags
- Cloud sync handled directly by the app (use SAF backup to a Drive folder instead — same effect, no provider lock-in)
- Auto-scheduled backup (WorkManager) — backup is manual-trigger for now
- Android 7.0 (API 24) or newer
- Google Play Services on the device (the ML Kit document scanner module is downloaded through Play Services on first use — comes pre-installed on every consumer Android phone)
The project is a standard Gradle Android build. You need:
- JDK 17 or 21 (the bundled
gradlewscript picks up whateverjavayou pointJAVA_HOMEat; Android Studio's JBR works out of the box) - Android SDK with platform 35 + build-tools 35 (Android Studio installs these by default)
./gradlew :app:assembleDebug # build a debug APK
./gradlew :app:installDebug # install on a connected deviceThe debug APK lands in app/build/outputs/apk/debug/.
./gradlew :app:testDebugUnitTest # local JVM + Robolectric (no device)
./gradlew :app:pixel6api36DebugAndroidTest # on-device suite on a managed headless emulator
./gradlew :app:connectedDebugAndroidTest # on-device suite against a plugged-in phoneThe pixel6api36 device is provisioned automatically the first time
you run it (a google_apis_playstore system image is downloaded —
~1 GB). After that runs are fast and offline.
| Suite | Files | What it covers |
|---|---|---|
| Local | ScanStoreTest, ShareFormatTest, SharingTest, ScanViewModelTest |
persistence, intent shape, PNG re-encode cache, ViewModel state |
| On-device | SharingFileProviderTest, MigsScanAppUiTest, ScanFlowEndToEndTest |
real FileProvider URIs, Compose screens, scan → persist → share round-trip |
The local suite runs in CI on every push; the on-device suite is intended to run against a plugged-in phone or an emulator.
- Kotlin 2.1 + Jetpack Compose (Material 3)
- CameraX-free — all capture goes through ML Kit's
play-services-mlkit-document-scanner, which launches its own polished scanner UI - AndroidX FileProvider for share-sheet URIs
- Robolectric + JUnit 4 locally, Compose
ui-test-junit4on-device
app/
src/main/java/dev/migs/scan/
MainActivity.kt # hosts the Compose tree
data/ # Scan, ScanPayload, ScanStore
share/ # ShareFormat, Sharing (intent builders)
ui/ # MigsScanApp, ScanViewModel, ScannerLauncher
src/test/ # local JVM / Robolectric suite
src/androidTest/ # on-device suite
tools/icon.svg # source for the launcher icon (re-export with ImageMagick)
.github/workflows/ci.yml # build + unit tests on every push