---
title: "Custom Settings, Info and Outline UI"
canonical_url: "https://www.nutrient.io/guides/android/samples/custom-settings-info-and-outline-ui-kotlin/"
md_url: "https://www.nutrient.io/guides/android/samples/custom-settings-info-and-outline-ui-kotlin.md"
last_updated: "2026-11-02T14:08:15.330Z"
description: "Replaces the settings, document info and outline screens with your own UI, reading and writing the SDK data through public API only."
---

# Custom Settings, Info and Outline UI

Replaces the settings, document info and outline screens with your own UI, reading and writing the SDK data through public API only.

[Get Started](https://www.nutrient.io/sdk/android/getting-started.md)

[All Samples](https://www.nutrient.io/guides/android/samples.md)

[Download](https://www.nutrient.io/guides/android/downloads.md)

[Launch Demo](https://www.nutrient.io/demo/)

---

```kotlin

/*
 *   Copyright © 2026 PSPDFKit GmbH. All rights reserved.
 *
 *   The PSPDFKit Sample applications are licensed with a modified BSD license.
 *   Please see License for details. This notice may not be removed from this file.
 */

package com.pspdfkit.catalog.examples.kotlin

import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.view.ViewGroup
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Switch
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import com.pspdfkit.annotations.actions.GoToAction
import com.pspdfkit.catalog.R
import com.pspdfkit.catalog.SdkExample
import com.pspdfkit.catalog.tasks.ExtractAssetTask
import com.pspdfkit.configuration.activity.PdfActivityConfiguration
import com.pspdfkit.configuration.page.PageLayoutMode
import com.pspdfkit.configuration.page.PageScrollDirection
import com.pspdfkit.configuration.page.PageScrollMode
import com.pspdfkit.configuration.theming.ThemeMode
import com.pspdfkit.document.OutlineElement
import com.pspdfkit.document.PageBinding
import com.pspdfkit.document.PdfDocument
import com.pspdfkit.preferences.PSPDFKitPreferences
import com.pspdfkit.ui.PdfActivity
import com.pspdfkit.ui.PdfActivityIntentBuilder
import io.nutrient.ui.settings.SettingsOptions
import io.nutrient.ui.settings.TIMEOUT_DEFAULT
import io.nutrient.ui.settings.TIMEOUT_INFINITE
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.DateFormat

/**
 * Shows how to replace the SDK's settings, document info and outline UI with your own, driven by the
 * SDK's own data.
 *
 * Everything here uses public API. No SDK class had to be moved or made public. Each of the three
 * screens is a view over data you can already reach:
 *
 * - Settings is a view over the active [PdfActivityConfiguration], [PdfActivity.getScreenTimeout]
 *   and [PSPDFKitPreferences]. [SettingsOptions] is public and works as the carrier.
 * - Document info is a view over [PdfDocument.getPdfMetadata], [PdfDocument.getPageBinding] and a
 *   few document properties. Every metadata getter is nullable, so read them defensively.
 * - The outline is a view over [PdfDocument.getOutlineAsync], which emits public [OutlineElement]s.
 *
 * The toolbar items are intercepted with `setOnToolbarItemClickListener`, which the SDK consults
 * before its own default action. Returning `true` suppresses the built-in screen and leaves the
 * toolbar untouched, so there is no need to disable items and add your own.
 */
class CustomSdkUiExample(context: Context) :
    SdkExample(context, R.string.customSdkUiExampleTitle, R.string.customSdkUiExampleDescription) {
    override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) {
        ExtractAssetTask.extract(WELCOME_DOC, title, context) { documentFile ->
            val intent = PdfActivityIntentBuilder.fromUri(context, Uri.fromFile(documentFile)).configuration(configuration.build()).activityClass(CustomSdkUiActivity::class).build()
            context.startActivity(intent)
        }
    }
}

/** Which of our own panes is showing. */
private enum class CustomPane(val label: String) {
    Settings("Settings"),
    DocumentInfo("Document info"),
    Outline("Outline"),
}

/** The editable and read-only values our document info pane shows. */
data class CustomDocumentInfo(
    val title: String,
    val author: String,
    val subject: String,
    val keywords: String,
    val pageBinding: PageBinding,
    val isEditable: Boolean,
    val readOnlyRows: List<Pair<String, String>>,
)

/** One outline row, flattened out of the [OutlineElement] tree so it can be shown as a list. */
data class CustomOutlineRow(val title: String, val depth: Int, val pageLabel: String?, val pageIndex: Int?)

/**
 * A [PdfActivity] that keeps the standard settings, document info and outline toolbar items but
 * opens its own UI for each of them.
 */
class CustomSdkUiActivity : PdfActivity() {
    private var pane by mutableStateOf<CustomPane?>(null)
    private var outlineRows by mutableStateOf<List<CustomOutlineRow>>(emptyList())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setOnToolbarItemClickListener { id ->
            when (id) {
                MENU_OPTION_SETTINGS -> {
                    pane = CustomPane.Settings
                    true
                }

                MENU_OPTION_DOCUMENT_INFO -> {
                    pane = CustomPane.DocumentInfo
                    true
                }

                MENU_OPTION_OUTLINE -> {
                    loadOutline()
                    pane = CustomPane.Outline
                    true
                }

                else -> false
            }
        }

        // Host our own Compose UI above the document. The activity is the lifecycle owner, so a
        // ComposeView added to the content view needs no further wiring.
        val content = findViewById<ViewGroup>(android.R.id.content)
        content.addView(
            ComposeView(this).apply {
                setContent {
                    MaterialTheme {
                        val current = pane
                        if (current!= null) {
                            CustomSdkUiSheet(
                                initialPane = current,
                                settings = readSettings(),
                                documentInfo = document?.let(::readDocumentInfo),
                                outlineRows = outlineRows,
                                onDismiss = { pane = null },
                                onApplySettings = { changed ->
                                    pane = null
                                    applySettings(changed)
                                },
                                onSaveDocumentInfo = { edited ->
                                    pane = null
                                    saveDocumentInfo(edited)
                                },
                                onOutlineRowClick = { row ->
                                    pane = null
                                    row.pageIndex?.let { setPageIndex(it) }
                                },
                            )
                        }
                    }
                }
            },
        )
    }

    // Settings -------------------------------------------------------------------------------

    /** Reads the values the SDK's own settings dialog is opened with. */
    private fun readSettings(): SettingsOptions {
        val pdfConfiguration = configuration.configuration
        return SettingsOptions(
            scrollDirection = pdfConfiguration.scrollDirection,
            scrollMode = pdfConfiguration.scrollMode,
            layoutMode = pdfConfiguration.layoutMode,
            themeMode = pdfConfiguration.themeMode,
            screenTimeoutMillis = screenTimeout,
            visibleItems = configuration.settingsMenuItemShown,
            sepia = pdfConfiguration.isSepia,
        )
    }

    /** Applies changed settings back. */
    private fun applySettings(changed: SettingsOptions) {
        val preferences = PSPDFKitPreferences.get(this)
        screenTimeout = changed.screenTimeoutMillis

        // PdfConfiguration is a data class, so copy() is the supported way to derive one.
        // PdfConfiguration.Builder(existingConfiguration) is deprecated in favour of it.
        val pdfConfiguration = configuration.configuration.copy(
            scrollDirection = changed.scrollDirection,
            scrollMode = changed.scrollMode,
            layoutMode = changed.layoutMode,
            isSepia = changed.sepia,
        )

        // Changing the configuration recreates the document view, so do this last.
        configuration = PdfActivityConfiguration.Builder(configuration).configuration(pdfConfiguration).themeMode(changed.themeMode).build()
    }

    // Document info --------------------------------------------------------------------------

    /** Reads the values the SDK's own document info screen shows. */
    private fun readDocumentInfo(document: PdfDocument): CustomDocumentInfo {
        val metadata = document.pdfMetadata
        val dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT)
        return CustomDocumentInfo(
            title = metadata.title?: "",
            author = metadata.author?: "",
            subject = metadata.subject?: "",
            keywords = metadata.keywords?.joinToString(", ")?: "",
            pageBinding = document.pageBinding,
            // A document that cannot be saved is shown, but not offered for editing.
            isEditable = document.isWritableAndCanSave,
            readOnlyRows = listOfNotNull(
                "Pages" to document.pageCount.toString(),
                metadata.producer?.let { "PDF producer" to it },
                metadata.creator?.let { "Content creator" to it },
                metadata.creationDate?.let { "Created" to dateFormat.format(it) },
                metadata.modificationDate?.let { "Modified" to dateFormat.format(it) },
            ),
        )
    }

    /**
     * Writes the edited values back and saves. [PdfDocument.saveIfModified] does disk work and can
     * throw, so it belongs off the main thread.
     */
    private fun saveDocumentInfo(edited: CustomDocumentInfo) {
        val document = document?: return
        val metadata = document.pdfMetadata
        metadata.title = edited.title.ifBlank { null }
        metadata.author = edited.author.ifBlank { null }
        metadata.subject = edited.subject.ifBlank { null }
        metadata.keywords = edited.keywords.split(',').map { it.trim() }.filter { it.isNotEmpty() }.ifEmpty { null }
        document.pageBinding = edited.pageBinding

        lifecycleScope.launch {
            val message = try {
                if (withContext(Dispatchers.IO) { document.saveIfModified() }) {
                    "Document info saved"
                } else {
                    "Nothing to save"
                }
            } catch (e: Exception) {
                "Could not save: ${e.message}"
            }
            Toast.makeText(this@CustomSdkUiActivity, message, Toast.LENGTH_SHORT).show()
        }
    }

    // Outline --------------------------------------------------------------------------------

    /**
     * Reads the document outline. getOutlineAsync is used rather than getOutline because the
     * blocking form must not be called on the main thread.
     */
    private fun loadOutline() {
        val document = document?: return
        lifecycleScope.launch {
            outlineRows = try {
                val elements = withContext(Dispatchers.IO) { document.outlineAsync.blockingGet() }
                elements.flatten(depth = 0)
            } catch (e: Exception) {
                Toast.makeText(this@CustomSdkUiActivity, "Could not read the outline: ${e.message}", Toast.LENGTH_SHORT).show()
                emptyList()
            }
        }
    }

    /** Flattens the outline tree into indented rows. */
    private fun List<OutlineElement>.flatten(depth: Int): List<CustomOutlineRow> = flatMap { element ->
        listOf(
            CustomOutlineRow(
                title = element.title,
                depth = depth,
                pageLabel = element.pageLabel,
                pageIndex = (element.action as? GoToAction)?.pageIndex,
            ),
        ) + element.children.flatten(depth + 1)
    }
}

// UI -----------------------------------------------------------------------------------------

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun CustomSdkUiSheet(
    initialPane: CustomPane,
    settings: SettingsOptions,
    documentInfo: CustomDocumentInfo?,
    outlineRows: List<CustomOutlineRow>,
    onDismiss: () -> Unit,
    onApplySettings: (SettingsOptions) -> Unit,
    onSaveDocumentInfo: (CustomDocumentInfo) -> Unit,
    onOutlineRowClick: (CustomOutlineRow) -> Unit,
) {
    var pane by remember { mutableStateOf(initialPane) }

    ModalBottomSheet(
        onDismissRequest = onDismiss,
        sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
    ) {
        PrimaryTabRow(selectedTabIndex = pane.ordinal) {
            CustomPane.entries.forEach { entry ->
                Tab(
                    selected = entry == pane,
                    onClick = { pane = entry },
                    text = { Text(entry.label) },
                )
            }
        }
        Column(
            modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()).padding(horizontal = 24.dp, vertical = 12.dp),
            verticalArrangement = Arrangement.spacedBy(12.dp),
        ) {
            when (pane) {
                CustomPane.Settings -> SettingsPane(settings, onDismiss, onApplySettings)
                CustomPane.DocumentInfo -> DocumentInfoPane(documentInfo, onDismiss, onSaveDocumentInfo)
                CustomPane.Outline -> OutlinePane(outlineRows, onOutlineRowClick)
            }
        }
    }
}

@Composable
private fun SettingsPane(options: SettingsOptions, onDismiss: () -> Unit, onApply: (SettingsOptions) -> Unit) {
    // SettingsOptions holds plain mutable fields rather than Compose state, so edit a local copy and
    // hand a finished one back on apply.
    var scrollDirection by remember { mutableStateOf(options.scrollDirection) }
    var scrollMode by remember { mutableStateOf(options.scrollMode) }
    var layoutMode by remember { mutableStateOf(options.layoutMode) }
    var themeMode by remember { mutableStateOf(options.themeMode) }
    var keepScreenOn by remember { mutableStateOf(options.screenTimeoutMillis == TIMEOUT_INFINITE) }

    ChoiceRow("Scroll direction", PageScrollDirection.entries, scrollDirection) { scrollDirection = it }
    ChoiceRow("Page transition", PageScrollMode.entries, scrollMode) { scrollMode = it }
    ChoiceRow("Page layout", PageLayoutMode.entries, layoutMode) { layoutMode = it }
    ChoiceRow("Theme", ThemeMode.entries, themeMode) { themeMode = it }

    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.SpaceBetween,
    ) {
        Text("Keep screen on", style = MaterialTheme.typography.bodyLarge)
        Switch(checked = keepScreenOn, onCheckedChange = { keepScreenOn = it })
    }

    ActionRow(confirmLabel = "Apply", onDismiss = onDismiss) {
        // Reuse the SDK's own carrier, and copy() keeps the values this UI does not offer.
        onApply(
            options.copy().apply {
                this.scrollDirection = scrollDirection
                this.scrollMode = scrollMode
                this.layoutMode = layoutMode
                this.themeMode = themeMode
                screenTimeoutMillis = if (keepScreenOn) TIMEOUT_INFINITE else TIMEOUT_DEFAULT
            },
        )
    }
}

@Composable
private fun DocumentInfoPane(info: CustomDocumentInfo?, onDismiss: () -> Unit, onSave: (CustomDocumentInfo) -> Unit) {
    if (info == null) {
        Text("The document is still loading.")
        return
    }

    var title by remember { mutableStateOf(info.title) }
    var author by remember { mutableStateOf(info.author) }
    var subject by remember { mutableStateOf(info.subject) }
    var keywords by remember { mutableStateOf(info.keywords) }
    var pageBinding by remember { mutableStateOf(info.pageBinding) }

    if (!info.isEditable) {
        Text("This document cannot be saved, so the fields are read only.", style = MaterialTheme.typography.bodySmall)
    }

    listOf(
        Triple("Title", title) { value: String -> title = value },
        Triple("Author", author) { value: String -> author = value },
        Triple("Subject", subject) { value: String -> subject = value },
        Triple("Keywords, comma separated", keywords) { value: String -> keywords = value },
    ).forEach { (label, value, onChange) ->
        OutlinedTextField(
            value = value,
            onValueChange = onChange,
            label = { Text(label) },
            enabled = info.isEditable,
            modifier = Modifier.fillMaxWidth(),
        )
    }

    val bindings = listOf(PageBinding.LEFT_EDGE, PageBinding.RIGHT_EDGE)
    Text("Page binding", style = MaterialTheme.typography.labelLarge)
    SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
        bindings.forEachIndexed { index, binding ->
            SegmentedButton(
                selected = binding == pageBinding,
                onClick = { pageBinding = binding },
                enabled = info.isEditable,
                shape = SegmentedButtonDefaults.itemShape(index = index, count = bindings.size),
            ) {
                Text(if (binding == PageBinding.LEFT_EDGE) "Left" else "Right")
            }
        }
    }

    HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))

    info.readOnlyRows.forEach { (label, value) ->
        Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
            Text(label, style = MaterialTheme.typography.bodyMedium)
            Text(value, style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.End)
        }
    }

    ActionRow(confirmLabel = "Save", enabled = info.isEditable, onDismiss = onDismiss) {
        onSave(
            info.copy(
                title = title,
                author = author,
                subject = subject,
                keywords = keywords,
                pageBinding = pageBinding,
            ),
        )
    }
}

@Composable
private fun OutlinePane(rows: List<CustomOutlineRow>, onRowClick: (CustomOutlineRow) -> Unit) {
    if (rows.isEmpty()) {
        Text("This document has no outline.")
        return
    }
    rows.forEach { row ->
        Row(
            modifier = Modifier.fillMaxWidth().clickable(enabled = row.pageIndex!= null) { onRowClick(row) }.padding(start = (row.depth * 16).dp, top = 8.dp, bottom = 8.dp),
            horizontalArrangement = Arrangement.SpaceBetween,
        ) {
            Text(row.title, style = MaterialTheme.typography.bodyLarge)
            row.pageLabel?.let { Text(it, style = MaterialTheme.typography.bodyMedium) }?: row.pageIndex?.let { Text("${it + 1}", style = MaterialTheme.typography.bodyMedium) }
        }
        HorizontalDivider()
    }
}

/** A labelled single choice row over the values of one configuration enum. */
@Composable
private fun <T : Enum<T>> ChoiceRow(label: String, values: List<T>, selected: T, onSelect: (T) -> Unit) {
    Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
        Text(label, style = MaterialTheme.typography.labelLarge)
        SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
            values.forEachIndexed { index, value ->
                SegmentedButton(
                    selected = value == selected,
                    onClick = { onSelect(value) },
                    shape = SegmentedButtonDefaults.itemShape(index = index, count = values.size),
                ) {
                    Text(value.name.lowercase().replace('_', ' ').replaceFirstChar { it.uppercase() })
                }
            }
        }
    }
}

/** The dismiss and confirm buttons shared by the editable panes. */
@Composable
private fun ActionRow(confirmLabel: String, enabled: Boolean = true, onDismiss: () -> Unit, onConfirm: () -> Unit) {
    Row(
        modifier = Modifier.fillMaxWidth().padding(bottom = 24.dp),
        horizontalArrangement = Arrangement.End,
    ) {
        TextButton(onClick = onDismiss) { Text("Close") }
        Button(enabled = enabled, onClick = onConfirm) { Text(confirmLabel) }
    }
}

```

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.

---

## Related pages

- [Add LTV to Existing Signature](/guides/android/samples/add-ltv-to-existing-signature-kotlin.md)
- [AES Encrypted File](/guides/android/samples/aes-encrypted-file-java.md)
- [AI Assistant (Multiple Documents, Compose)](/guides/android/samples/ai-assistant-multiple-documents-compose-kotlin.md)
- [AI Assistant (Multiple Documents, ViewPager)](/guides/android/samples/ai-assistant-multiple-documents-viewpager-kotlin.md)
- [AI Assistant (Single Document)](/guides/android/samples/ai-assistant-single-document-kotlin.md)
- [Annotation Configuration](/guides/android/samples/annotation-configuration-kotlin.md)
- [Annotation Creation](/guides/android/samples/annotation-creation-kotlin.md)
- [Annotation Flags](/guides/android/samples/annotation-flags-kotlin.md)
- [Annotation Overlay](/guides/android/samples/annotation-overlay-java.md)
- [Annotation Rendering](/guides/android/samples/annotation-rendering-kotlin.md)
- [Annotation Selection Styling](/guides/android/samples/annotation-selection-styling-kotlin.md)
- [Annotation Sidebar](/guides/android/samples/annotation-sidebar-kotlin.md)
- [Annotation Toolbar: Custom Items](/guides/android/samples/annotation-toolbar-custom-items-kotlin.md)
- [Annotation Toolbar: Item Grouping](/guides/android/samples/annotation-toolbar-item-grouping-kotlin.md)
- [Annotation Toolbar: User-Editable Tools](/guides/android/samples/annotation-toolbar-user-editable-tools-kotlin.md)
- [Annotations with Transparency](/guides/android/samples/annotations-with-transparency-kotlin.md)
- [Application Policy](/guides/android/samples/application-policy-kotlin.md)
- [Bookmark Highlighting](/guides/android/samples/bookmark-highlighting-kotlin.md)
- [Compose Image Document](/guides/android/samples/compose-image-document-kotlin.md)
- [Compose Navigation](/guides/android/samples/compose-navigation-kotlin.md)
- [Compose PDF Viewer](/guides/android/samples/compose-pdf-viewer-kotlin.md)
- [Construction Floor Plan](/guides/android/samples/construction-floor-plan-kotlin.md)
- [Custom Activity Form Editing](/guides/android/samples/custom-activity-form-editing-java.md)
- [Custom Annotation Inspector](/guides/android/samples/custom-annotation-inspector-java.md)
- [Custom Data Provider](/guides/android/samples/custom-data-provider-kotlin.md)
- [Custom Download Dialog](/guides/android/samples/custom-download-dialog-java.md)
- [Custom Electronic Signature](/guides/android/samples/custom-electronic-signature-java.md)
- [Custom Form Highlight Color](/guides/android/samples/custom-form-highlight-color-java.md)
- [Custom Layout](/guides/android/samples/custom-layout-kotlin.md)
- [Custom Note Hinter](/guides/android/samples/custom-note-hinter-kotlin.md)
- [Custom Outline Provider](/guides/android/samples/custom-outline-provider-kotlin.md)
- [Custom Page Templates](/guides/android/samples/custom-page-templates-java.md)
- [Custom Search UI (Compose)](/guides/android/samples/custom-search-ui-compose-kotlin.md)
- [Custom Search UI (Views)](/guides/android/samples/custom-search-ui-views-java.md)
- [Custom Sharing Dialog](/guides/android/samples/custom-sharing-dialog-java.md)
- [Custom Sharing Menu](/guides/android/samples/custom-sharing-menu-java.md)
- [Custom Stamp Annotations](/guides/android/samples/custom-stamp-annotations-java.md)
- [Digital Signature (Basic)](/guides/android/samples/digital-signature-basic-kotlin.md)
- [Digital Signature (Manual)](/guides/android/samples/digital-signature-manual-kotlin.md)
- [Digital Signature (Third-Party)](/guides/android/samples/digital-signature-third-party-kotlin.md)
- [Digital Signature (Two-Step)](/guides/android/samples/digital-signature-two-step-kotlin.md)
- [Disabled Annotation Property](/guides/android/samples/disabled-annotation-property-java.md)
- [Document Comparison](/guides/android/samples/document-comparison-kotlin.md)
- [Document Download](/guides/android/samples/document-download-kotlin.md)
- [Document from Canvas](/guides/android/samples/document-from-canvas-kotlin.md)
- [Document Processing](/guides/android/samples/document-processing-kotlin.md)
- [Document Sharing](/guides/android/samples/document-sharing-java.md)
- [Document Switcher](/guides/android/samples/document-switcher-java.md)
- [DocumentView Composable](/guides/android/samples/documentview-composable-kotlin.md)
- [DocumentView in a Dialog](/guides/android/samples/documentview-in-a-dialog-kotlin.md)
- [Download Progress](/guides/android/samples/download-progress-kotlin.md)
- [Dynamic Pages on Scroll](/guides/android/samples/dynamic-pages-on-scroll-kotlin.md)
- [E-Learning](/guides/android/samples/e-learning-kotlin.md)
- [Electronic + Digital Signing](/guides/android/samples/electronic-digital-signing-kotlin.md)
- [External Document](/guides/android/samples/external-document-kotlin.md)
- [File Annotation Creation](/guides/android/samples/file-annotation-creation-kotlin.md)
- [Filterable Thumbnail Grid](/guides/android/samples/filterable-thumbnail-grid-kotlin.md)
- [Form Click Intercept (Compose)](/guides/android/samples/form-click-intercept-compose-kotlin.md)
- [Form Creation](/guides/android/samples/form-creation-kotlin.md)
- [Form Filling](/guides/android/samples/form-filling-kotlin.md)
- [Forms with JavaScript](/guides/android/samples/forms-with-javascript-kotlin.md)
- [Fragment Runtime Configuration](/guides/android/samples/fragment-runtime-configuration-kotlin.md)
- [Generate PDF Report](/guides/android/samples/generate-pdf-report-kotlin.md)
- [Hide and Reveal Areas](/guides/android/samples/hide-and-reveal-areas-kotlin.md)
- [HTML-to-PDF Conversion](/guides/android/samples/html-to-pdf-conversion-kotlin.md)
- [Image Document](/guides/android/samples/image-document-kotlin.md)
- [Inline Multimedia](/guides/android/samples/inline-multimedia-kotlin.md)
- [Instant Document JSON](/guides/android/samples/instant-document-json-kotlin.md)
- [Instant JSON Attachment](/guides/android/samples/instant-json-attachment-kotlin.md)
- [JavaScript Actions](/guides/android/samples/javascript-actions-kotlin.md)
- [JavaScript Calculator](/guides/android/samples/javascript-calculator-kotlin.md)
- [JavaScript Form Filling](/guides/android/samples/javascript-form-filling-kotlin.md)
- [Kiosk Grid](/guides/android/samples/kiosk-grid-kotlin.md)
- [LTV Signature](/guides/android/samples/ltv-signature-kotlin.md)
- [Main Toolbar: Custom Layout & Items](/guides/android/samples/main-toolbar-custom-layout-items-kotlin.md)
- [Main Toolbar: FAB Menu (M3 Expressive)](/guides/android/samples/main-toolbar-fab-menu-m3-expressive-kotlin.md)
- [Main Toolbar: Floating Pill (M3 Expressive)](/guides/android/samples/main-toolbar-floating-pill-m3-expressive-kotlin.md)
- [Measurement Tools](/guides/android/samples/measurement-tools-kotlin.md)
- [Memory Pressure Recovery](/guides/android/samples/memory-pressure-recovery-kotlin.md)
- [Merge Documents](/guides/android/samples/merge-documents-kotlin.md)
- [Multimedia Annotations](/guides/android/samples/multimedia-annotations-kotlin.md)
- [Multiple Documents (Compose Pager)](/guides/android/samples/multiple-documents-compose-pager-kotlin.md)
- [OCR](/guides/android/samples/ocr-kotlin.md)
- [Overlay Views](/guides/android/samples/overlay-views-kotlin.md)
- [Overlay Visibility](/guides/android/samples/overlay-visibility-kotlin.md)
- [Password Protected PDF](/guides/android/samples/password-protected-pdf-kotlin.md)
- [PDF from Image](/guides/android/samples/pdf-from-image-kotlin.md)
- [PdfFragment](/guides/android/samples/pdffragment-kotlin.md)
- [PdfUiFragment](/guides/android/samples/pdfuifragment-kotlin.md)
- [Playground](/guides/android/samples/playground-kotlin.md)
- [Popup Toolbar: Custom Items](/guides/android/samples/popup-toolbar-custom-items-kotlin.md)
- [Programmatic Zoom](/guides/android/samples/programmatic-zoom-kotlin.md)
- [Reader View](/guides/android/samples/reader-view-kotlin.md)
- [Remote URL](/guides/android/samples/remote-url-kotlin.md)
- [Replace and Refresh Documents](/guides/android/samples/replace-and-refresh-documents-kotlin.md)
- [Runtime Configuration](/guides/android/samples/runtime-configuration-kotlin.md)
- [Scientific Paper](/guides/android/samples/scientific-paper-kotlin.md)
- [Screen Reader](/guides/android/samples/screen-reader-java.md)
- [Search Indexing](/guides/android/samples/search-indexing-kotlin.md)
- [Selection Customization](/guides/android/samples/selection-customization-java.md)
- [Signature Parcelize](/guides/android/samples/signature-parcelize-kotlin.md)
- [Signature Storage Database](/guides/android/samples/signature-storage-database-kotlin.md)
- [Sound Extraction](/guides/android/samples/sound-extraction-kotlin.md)
- [Split Screen (Compose)](/guides/android/samples/split-screen-compose-kotlin.md)
- [Split View](/guides/android/samples/split-view-java.md)
- [Tabbed Documents (Compose)](/guides/android/samples/tabbed-documents-compose-kotlin.md)
- [Tabbed Documents](/guides/android/samples/tabbed-documents-kotlin.md)
- [Tabbed Documents (Persistent)](/guides/android/samples/tabbed-documents-persistent-kotlin.md)
- [Text Field Suggestions](/guides/android/samples/text-field-suggestions-kotlin.md)
- [Thumbnail Bar Modes](/guides/android/samples/thumbnail-bar-modes-kotlin.md)
- [Try Instant](/guides/android/samples/try-instant-kotlin.md)
- [UI View Modes](/guides/android/samples/ui-view-modes-kotlin.md)
- [Vertical Scrollbar](/guides/android/samples/vertical-scrollbar-java.md)
- [Watermarks](/guides/android/samples/watermarks-kotlin.md)
- [XFDF Import/Export](/guides/android/samples/xfdf-import-export-kotlin.md)

