On-Device OCR Notebook
Build an Android notebook app in Kotlin that turns photos of handwritten or printed notes, whiteboards and documents into searchable text, entirely on the phone. You take or pick a photo, the text is recognized on the device with Google's ML Kit (no internet needed and nothing leaves the phone), and it's saved with the image in a Room database with full-text search, so you can later find a note by any word in it. Recognition runs in the background, survives the app being closed, and can be retried. An optional Ktor server lets you back up notes when you choose to. You'll learn on-device machine learning with ML Kit, camera and image handling, Room full-text search (FTS), WorkManager, and designing an offline-first app.
- Estimate
- ~16h
- Steps
- 7
- Completed by
- 0
- Proposed by
- codeseed.app
Room · Ktor
Project roadmap
- 01
Design the app
~2hWrite ARCHITECTURE.md: a note has an image file, the recognized text split into blocks, a title, tags, created date and a status (pending, recognizing, done, failed). Describe the flow from capture to searchable note, where images are stored, how search works, and what the optional backup sends. Set up a Jetpack Compose project with Room, WorkManager and ML Kit text recognition. Done when: the project builds, and ARCHITECTURE.md covers the flow and statuses.
- 02
Capture and store images
~2hLet users take a photo with the camera (through CameraX or the system camera intent) or pick one from the gallery. Copy the image into the app's private storage, fix its rotation using EXIF data, and shrink very large images. Create the note in Room with status pending. Done when: captured and picked images appear as pending notes, correctly rotated.
- 03
Recognize text on the device
~2.5hCreate a WorkManager worker that runs ML Kit text recognition on a pending note's image, stores the full text and the blocks with their positions, and marks the note done, or failed with the reason. Workers survive the app closing, and failed notes can be retried. Recognize one image at a time to limit memory use. Done when: photos of printed text become notes with the right text, even if the app is closed during recognition.
- 04
Add full-text search
~2.5hAdd a Room FTS4 table linked to the notes, indexing the title, tags and recognized text, kept in sync when notes change. Build a search screen that queries it with MATCH as you type (supporting prefix search such as meet*), and shows matching notes with the matching words highlighted in a snippet. Done when: searching any word from a photographed note finds it instantly, offline.
- 05
Build the notebook screens
~2.5hBuild the note list (newest first, with thumbnails and status), a note detail screen showing the image with the recognized text blocks outlined on top, and editing of the title, tags and text to fix recognition mistakes (which updates the search index). Deleting a note also deletes its image file. Done when: notes can be browsed, corrected and deleted, and corrections are searchable.
- 06
Add optional backup with Ktor
~2.5hBuild a small Ktor server with an upload endpoint protected by a token, and an opt-in backup setting in the app. Upload changed notes with a WorkManager job that needs Wi-Fi, using the note id as an idempotency key so retries don't create duplicates. Nothing is uploaded unless the user turns backup on. Done when: with backup on, notes reach the server once, and with it off, nothing is sent.
- 07
Test it
~2hWrite tests: Room DAO and FTS queries with an in-memory database (including prefix search and updates), the recognition worker with a fake recognizer returning text or an error, and the Ktor endpoint with testApplication. Test by hand with poor photos (blurry, dark, angled) and note the results in README.md. Done when: the tests pass, and README.md describes recognition quality.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack