How kobotoolbox/collect works
1. Overall shape
KoboCollect is a large Android monorepo built as many Gradle modules. The main application is collect_app, and most functionality is split into reusable feature/library modules so the app can be assembled from shared building blocks.
2. Primary runtime
The product runs as an Android app using a mix of Kotlin and Java, with Activities, Fragments, ViewModels, and Android services as the top-level UI/runtime boundary. Dependency injection is used heavily through Dagger setup classes in multiple modules.
3. Core product flow
The center of the architecture is form collection: users download blank forms, fill them out, save drafts, finalize submissions, and upload instances. That flow crosses several modules: form management, form entry, instance management, saving/finalization, and network sync.
4. Form system
The forms, forms-test, and test-forms modules define the shared form model and test fixtures. In the app, form parsing, loading, hierarchy rendering, widgets, media handling, and validation live under collect_app/src/main/java/org/odk/collect/android/formentry, widgets, formhierarchy, and formmanagement.
5. Local persistence boundary
Local data is split into repositories over SQLite and app settings over shared preferences. The db module provides low-level SQLite helpers/migrations, while app repositories such as forms, instances, savepoints, entities, and projects wrap the database or settings store behind domain-friendly APIs.
6. Projects and settings
A “project” is a first-class boundary in the app. The projects and settings modules handle project creation, migration, configuration import, server credentials, and preference schemas. The app’s project-aware behavior is driven by these modules rather than hardcoded global state.
7. Server communication
Network interaction is centered on OpenRosa/ODK-style endpoints. The open-rosa module provides HTTP and XML fetching/parsing, while collect_app uses it for form discovery, download, and instance upload. This boundary separates protocol handling from app-specific form/instance logic.
8. Background work and sync
Sync-like tasks are handled asynchronously rather than inline with the UI. The async module provides scheduler abstractions and WorkManager/coroutine integration, and collect_app/backgroundwork wires these into form updates, instance submission, and recurring maintenance jobs.
9. Media, sensors, and device capabilities
Several features are device-centric and isolated into modules: location for GPS tracking, audio-recorder and audio-clips for recording/playback, selfie-camera for capture, draw for annotation, qr-code for scanning/encoding, and geo/maps for map-based question input. These modules keep hardware-specific logic separate from core form flows.
10. Maps and geo rendering
Map support is abstracted behind maps, with concrete providers in google-maps, mapbox, and osmdroid. The app chooses a map implementation through configurator/factory layers, so geo questions can render against different backends without changing the higher-level form logic.
11. Cross-cutting utilities
Shared foundations live in modules like shared, androidshared, material, lists, image-loader, permissions, analytics, metadata, external-app, notifications, and strings. These contain reusable UI widgets, file/path utilities, permissions checks, localization, analytics wrappers, and generic result/lock helpers used across the app.
12. External integration surfaces
The app exposes Android activities, content providers, and intent-based entry points for other apps and system flows. Modules such as external-app, web-page, errors, and crash-handler represent boundaries for external launch, browser/web content, error display, and crash handling.
13. Entities and specialized workflows
Entities are a separate product capability with their own storage, parsing, and browser UI in the entities module, plus app-side integration under collect_app/entities. This is a distinct flow from ordinary form submissions and has its own parse/finalize/filter pipeline.
14. Testing architecture
The repo is test-heavy and organized by module. It includes Robolectric/unit tests per module, Android instrumented tests in collect_app/src/androidTest, reusable test helpers in test-shared, and dedicated fixture modules like test-forms and forms-test to keep product behavior testable across the monorepo.
Main entry points: collect_app Collect app · formentry Form entry · forms Forms API · geo Geo input
Components 25
Android app
Main Collect application and its in-app subsystems.
- Collect app · Main Android application shell, UI, flows, initialization, and feature wiring.
collect_app - Form mgmt · Coordinates blank-form discovery, download, metadata, and finalization.
collect_app/src/main/java/org/odk/collect/android/formmanagement - Form entry · Runs the form-filling session, widgets, validation, saving, and end-of-form logic.
collect_app/src/main/java/org/odk/collect/android/formentry - Instances · Handles drafts, finalization, submission, deletion, and autosend.
collect_app/src/main/java/org/odk/collect/android/instancemanagement - Projects · Project creation, reset, deletion, and project-specific settings flow.
collect_app/src/main/java/org/odk/collect/android/projects - Settings UI · Project and app preference screens, dialogs, and preference wiring.
collect_app/src/main/java/org/odk/collect/android/preferences - Background work · App-side schedulers and task specs for sync, updates, and maintenance jobs.
collect_app/src/main/java/org/odk/collect/android/backgroundwork - Main menu · Home screen, permissions gate, and primary navigation into the app.
collect_app/src/main/java/org/odk/collect/android/mainmenu - Entities · App integration for entity parsing, finalization, and browser UI.
collect_app/src/main/java/org/odk/collect/android/entities
Core libraries
Reusable libraries that define shared domain, storage, protocol, and infrastructure.
- SQLite core · Low-level SQLite helpers, migrations, and database connection primitives.
db - Forms API · Shared form, instance, and savepoint domain model and repository interfaces.
forms - Projects API · Project model, repository, and configuration abstractions.
projects - Settings API · Settings schemas, migrations, validation, and import/export helpers.
settings - OpenRosa · HTTP/XML client and parser for OpenRosa-style server communication.
open-rosa - Async core · Coroutine and WorkManager scheduler abstractions plus network state helpers.
async - Shared utils · Pure shared utilities for files, strings, result types, locks, and collections.
shared - Android shared · Reusable Android utilities for UI, system integration, bitmaps, and lifecycle helpers.
androidshared
Feature modules
Optional or specialized runtime modules assembled into the app.
- Maps core · Map abstractions, fragments, view models, markers, and offline layer support.
maps - Geo input · Geopoint and geopoly capture UI and location-aware question workflows.
geo - Location · Location client abstraction, fused/GPS providers, and tracking services.
location - Audio · Audio recording and playback feature modules for form questions.
audio-recorder - QR code · Barcode scanning and QR generation/decoding for configuration and form input.
qr-code - Media capture · Selfie capture, drawing, image loading, printing, and other media-related capabilities.
selfie-camera
Test support
Shared fixtures and cross-module test helpers.
- Test shared · Reusable test fixtures, matchers, fake schedulers, and activity helpers.
test-shared - Form fixtures · Reusable form and instance fixtures for module-level tests.
forms-test
Connections 37
- Collect app → Form mgmt: owns · App wires the form management flow.
- Collect app → Form entry: owns · App hosts the form entry runtime.
- Collect app → Instances: owns · App hosts draft and submission flows.
- Collect app → Projects: owns · App hosts project management.
- Collect app → Settings UI: owns · App renders settings and preference screens.
- Collect app → Background work: schedules · App triggers async sync and maintenance jobs.
- Collect app → Main menu: starts · Main menu is the entry point.
- Collect app → Entities: integrates · App exposes entity workflows.
- Form mgmt → OpenRosa: fetches forms · Downloads form lists and form files.
- Form mgmt → Forms API: uses · Operates on form domain objects.
- Form entry → Forms API: loads forms · Consumes form model and savepoints.
- Form entry → Location: uses · Supports geopoint and background location questions.
- Form entry → Audio: uses · Supports audio questions and recording.
- Form entry → QR code: uses · Supports barcode and QR question types.
- Form entry → Geo input: renders · Opens geo input screens and map questions.
- Instances → Forms API: persists instances · Tracks drafts, instances, and savepoints.
- Instances → OpenRosa: uploads instances · Submits finalized instances to server endpoints.
- Projects → Projects API: wraps · App-specific project UI sits on project domain APIs.
- Settings UI → Settings API: reads schema · Preferences are driven by settings definitions and migrations.
- Settings UI → Projects API: applies · Project-specific settings are stored and migrated per project.
- Background work → Async core: uses · Background jobs run through scheduler abstractions.
- Background work → OpenRosa: syncs · Background tasks call server communication paths.
- Main menu → Projects API: depends on · Menu shows and switches current project.
- Entities → Forms API: extends · Entity workflows build on form and finalization concepts.
- Entities → Collect app: hooks into · App-side entity integration joins the main runtime.
- SQLite core → Forms API: backing store · Forms repositories sit on SQLite helpers and migrations.
- SQLite core → Projects API: backing store · Project state can be persisted through shared database helpers.
- SQLite core → Settings API: supports migrations · Settings import/migration logic works with stored data.
- Android shared → Shared utils: builds on · Android utilities complement common shared primitives.
- Maps core → Geo input: renders map input · Map abstractions power geo question UIs.
- Geo input → Location: tracks position · Geo workflows depend on location providers and tracking.
- Geo input → Maps core: uses maps · Geo input delegates to map abstractions and providers.
- QR code → Collect app: used by · App configuration and form entry launch scanner flows.
- Audio → Collect app: used by · App embeds recorder and player flows in form entry.
- Media capture → Collect app: used by · Media-related capabilities surface through the app.
- Test shared → Collect app: supports tests · Shared test helpers are consumed by app tests.
- Form fixtures → Forms API: fixtures for · Reusable sample forms and repositories support core form tests.