PDF 8 min read

AndroidX PDF 1.0.0-alpha19: Editable Forms, Public Annotations, and OCR — The Third-Party Killer Gets Serious

PDF support on Android has been a mess for years. The platform-level PdfRenderer class has existed since API 21, but it's strictly a reader — no editing, no annotations, no text extraction from scanned pages. So every app that needed anything beyond render-and-display ended up pulling in a third-party SDK: iText, MuPDF, PDFium bindings, or a heavyweight commercial library that added 10MB+ to the APK and came with licensing headaches.

The Jetpack PDF library, now at version 1.0.0-alpha19 (released July 1, 2026), is Google's long-overdue answer to this. And alpha19 specifically is the release where it stops being a viewer with aspirations and starts looking like something you could genuinely replace a third-party dependency with. Three meaningful capabilities landed in this drop: inline form filling via a public EditablePdfDocument API, image-based text recognition through OcrProvider, and the architectural split that makes the whole library composable — a dedicated pdf-core module that separates document models from the view layer.

pdf-core
New module separating document model from UI
Forms
Inline editable fields with autofill support
OCR
OcrProvider APIs for scanned document text

The pdf-core Split: Architecture That Actually Scales

Until alpha19, the Jetpack PDF library was effectively one artifact: pdf-viewer-fragment. If you wanted to work with a PDF document programmatically — read its structure, parse fields, process content — you were tied to the view layer too. That's a coupling problem. You don't want to depend on a Fragment and a full UI stack just to extract form field values or run text recognition on a server-side job.

Alpha19 introduces pdf-core as a separate artifact that houses the document models independently of any view code. The PdfDocument and related APIs live there now, and the pdf-viewer-fragment artifact depends on pdf-core rather than containing everything itself.

In practice, this means you can now add just pdf-core if your use case is document processing without a viewer:

dependencies {
    // View-layer PDF viewer (includes pdf-core transitively)
    implementation("androidx.pdf:pdf-viewer-fragment:1.0.0-alpha19")

    // Or just the document model layer — no Fragment, no UI
    implementation("androidx.pdf:pdf-core:1.0.0-alpha19")
}

This matters more than it might look. If you're building a background document processor — say, a receipts scanner that extracts totals from uploaded PDFs, or a contract parser that reads and validates form field values before ingestion — you previously had no good Jetpack option. You either carried the full viewer stack you didn't need, or you used a third-party library for the document model piece. Now there's a clean boundary.

EditablePdfDocument: Inline Form Filling With Autofill

This is the one that'll make the most immediate difference for apps that deal with business documents. EditablePdfDocument is a new interface extending PdfDocument, designed specifically for documents that contain fillable form fields. It's now public in alpha19, which means you can open a PDF, interact with its form fields in code, and apply changes — all within the standard Jetpack API surface.

EditablePdfViewerFragment wires everything together for the interactive case. Drop it into a layout and your users get inline tapping and editing on text fields, checkboxes, radio buttons, and dropdowns — no WebView, no fullscreen PDF viewer SDK, no "hand this off to an external app" UX.

// In your Fragment or Activity
val pdfUri = /* your document URI */

val viewerFragment = EditablePdfViewerFragment.newInstance(pdfUri)
supportFragmentManager.beginTransaction()
    .replace(R.id.pdf_container, viewerFragment)
    .commit()

// Access the document model once loaded
viewerFragment.pdfDocumentLiveData.observe(this) { document ->
    if (document is EditablePdfDocument) {
        // Enumerate form fields
        val fields = document.getFormFields()
        fields.forEach { field ->
            Log.d("PDF", "Field: ${field.name}, type: ${field.type}")
        }
    }
}

Autofill support is bundled in. The fragment hooks into the Android Autofill framework, so if a user has saved their name, address, or standard form data in their autofill provider, that data can be suggested for matching PDF form fields without you writing any autofill integration code. For apps in fintech, insurance, or anything involving regulatory PDFs — this is significant. The alternative was either building a custom bridge to the autofill API yourself, or pointing users toward "download this and fill it in Adobe."

Field types supported: text inputs, dropdowns, checkboxes, and radio buttons. Multi-page form navigation works inline — no pagination UX to build yourself.

AnnotationView and Public Annotation APIs

Alpha19 makes AnnotationView and the annotation-related classes fully public. Previously these were internal or restricted, which meant you couldn't overlay custom annotation UI on top of the PDF viewer or read/write annotation data in a documented way. Now you can.

EditablePdfDocument exposes the annotation model too, so reading existing annotations — highlights, comments, markup — is part of the same API surface as form field access. This is the foundation for review workflows: display a contract, let the user annotate sections, persist those annotations back to the document or to your own backend.

// Reading existing annotations from a loaded document
val annotations = (document as? EditablePdfDocument)
    ?.getAnnotations(pageIndex = 0)
    ?: emptyList()

annotations.forEach { annotation ->
    when (annotation.type) {
        AnnotationType.HIGHLIGHT -> { /* ... */ }
        AnnotationType.NOTE      -> { /* ... */ }
        else -> { /* ... */ }
    }
}

I've seen this pattern come up in Nodat's document handling — when users attach reference materials to notes, being able to extract highlighted sections or comments programmatically would have saved several workarounds we built on top of third-party libraries. The fact that this is now a first-class Jetpack API with documented stability expectations changes the calculus significantly.

OcrProvider: Text from Scanned Documents

Text-based PDFs (those generated digitally from Word, Google Docs, or a PDF export) already support text extraction through the existing layer model. The hard case has always been scanned documents — PDFs that are essentially a sequence of JPEG images of paper pages. There's no embedded text layer, so search, copy, and any kind of content processing fails silently.

OcrProvider is the hook point for plugging in image-based text recognition. The API is deliberately provider-agnostic: you implement OcrProvider with whatever recognition engine you want — ML Kit's text recognition, Tesseract, or a cloud OCR service — and the PDF library calls it when text extraction is requested on a page with no embedded text layer.

class MlKitOcrProvider : OcrProvider {
    override suspend fun recognizeText(
        pageImage: Bitmap,
        pageIndex: Int
    ): OcrResult {
        val recognizer = TextRecognition.getClient(
            TextRecognizerOptions.DEFAULT_OPTIONS
        )
        return suspendCancellableCoroutine { cont ->
            recognizer.process(InputImage.fromBitmap(pageImage, 0))
                .addOnSuccessListener { visionText ->
                    cont.resume(OcrResult.success(visionText.text))
                }
                .addOnFailureListener { e ->
                    cont.resume(OcrResult.failure(e))
                }
        }
    }
}

// Register it when building the viewer
val viewerFragment = PdfViewerFragment.newInstance(
    uri = pdfUri,
    ocrProvider = MlKitOcrProvider()
)

The OCR integration is fully coroutine-aware — recognizeText is a suspend function, so you can use ML Kit's task API, a Flow-based pipeline, or even a remote call without blocking the UI thread. The library handles page lifecycle and cancellation when the user scrolls past a page before recognition completes.

For Samachar, where users sometimes attach scanned news clippings as images embedded in documents, this kind of OCR hook would have replaced a custom ML Kit integration I wired up at the app layer. Having it as part of the PDF viewer's official API means it gets handled at the right abstraction level — the viewer knows the page dimensions, DPI, and render context in a way that app-level code has to approximate.

Breaking Changes: Two Deprecations Finally Removed

Alpha19 also cleans house on two APIs that have been deprecated for a while. If you're already on a recent alpha, you've likely migrated — but if you're picking up the library fresh, know these are gone:

// Before (removed)
override fun onLoadDocumentSuccess() {
    // no document reference
}

// After
override fun onLoadDocumentSuccess(document: PdfDocument) {
    // document is available here
    val isLinearized = document.linearizationStatus == LinearizationStatus.LINEARIZED
}

Bug Fixes Worth Noting

Two bugs that affected real user interactions were fixed alongside the API work:

Horizontal scrolling at page edges was unreliable because the touch event interception logic wasn't accounting for scroll direction. On wide PDFs (landscape documents, spreadsheets) where users need to scroll horizontally within a page, the swipe gesture would sometimes get intercepted by the outer scroll container instead of the page-level scroll. Fixed in this release.

Fast scroller visibility in accessibility mode was inconsistent — when accessibility services were active, the fast scroller would sometimes not appear. Since the fast scroller is a primary navigation mechanism for long documents, this was a meaningful accessibility regression. It's resolved in alpha19.

Should You Adopt This Now?

Split this into two decisions, same as any alpha library.

If you're currently pulling in a third-party PDF library solely for its viewer functionality — render pages, scroll through a multi-page document, basic zoom — the Jetpack PDF viewer has been usable since the early alphas, and alpha19 doesn't introduce any regressions there. Swapping a heavyweight SDK for the Jetpack viewer at this stage is a reasonable trade, especially given the APK size and licensing benefits.

If you need form filling, annotation access, or OCR, alpha19 is the first release where these APIs are genuinely public and usable. They're still alpha — meaning signatures could change before 1.0.0 stable — but the direction is clear and the architecture is now sound with the pdf-core split. I'd prototype the form filling and OCR integrations now, build against them internally, and be ready to ship when the library hits RC or stable.

The one case I'd still wait: if your app relies on heavy commercial PDF features — digital signatures with certificate validation, complex layer management, PDF/A compliance — the Jetpack library isn't there yet. Stay with a dedicated SDK for those. For the 80% case of "display a PDF and let users fill in the form," alpha19 is a credible path.

The broader trajectory is what matters most here. Google is clearly building toward a comprehensive first-party PDF stack on Android — one that doesn't require every developer to solve the same licensing and integration problem independently. The pdf-core split in particular signals they're thinking about this as a platform-level capability, not just a viewer widget. That's the kind of investment you back as a developer who doesn't want to be on the wrong side of a platform transition two years from now.

Comments 0

No comments yet. Be the first to leave one!

Leave a comment