---
title: "Bookmark Highlighting"
canonical_url: "https://www.nutrient.io/guides/android/samples/bookmark-highlighting-kotlin/"
md_url: "https://www.nutrient.io/guides/android/samples/bookmark-highlighting-kotlin.md"
last_updated: "2026-05-15T19:10:04.916Z"
description: "Display bookmark indicators on pages in the thumbnail bar and grid using PdfDrawableProvider."
---

# Bookmark Highlighting

Display bookmark indicators on pages in the thumbnail bar and grid using PdfDrawableProvider.

[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 © 2020-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.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.view.Gravity
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.pspdfkit.bookmarks.Bookmark
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.activity.ThumbnailBarMode
import com.pspdfkit.document.PdfDocument
import com.pspdfkit.ui.PdfActivity
import com.pspdfkit.ui.PdfActivityIntentBuilder
import com.pspdfkit.ui.drawable.PdfDrawable
import com.pspdfkit.ui.drawable.PdfDrawableProvider
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.Disposable
import kotlin.math.roundToInt

private val initialThumbnailBarMode = ThumbnailBarMode.THUMBNAIL_BAR_MODE_SCROLLABLE

/**
 * Example showing how to use the drawable API to put a drawn highlight on all pages that contain a bookmark.
 */
class BookmarkHighlightingExample(context: Context) :
    SdkExample(context, R.string.bookmarkHighlightingExampleTitle, R.string.bookmarkHighlightingExampleDescription) {
    override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) {
        // This uses larger thumbnails making our bookmark indicator more easily visible.
        configuration.setThumbnailBarMode(initialThumbnailBarMode).title("Bookmark Indicator")

        // Start the activity once the example document has been extracted from the app's assets.
        ExtractAssetTask.extract(BOOKMARK_DOCUMENT, title, context) { documentFile ->
            val intent =
                PdfActivityIntentBuilder.fromUri(context, Uri.fromFile(documentFile)).configuration(configuration.build()).activityClass(BookmarkHighlightingActivity::class).build()

            // Start the BookmarkHighlightingActivity for the extracted document.
            context.startActivity(intent)
        }
    }

    companion object {
        const val BOOKMARK_DOCUMENT = "bookmark_highlight_example.pdf"
    }
}

class BookmarkHighlightingActivity : PdfActivity() {
    private lateinit var toggleThumbnailBarModeFab: FloatingActionButton

    /** List of bookmarks that current exist in the document. */
    private val currentBookmarks = mutableListOf<Bookmark>()

    private var currentThumbnailBarMode = initialThumbnailBarMode
    private var currentToast: Toast? = null

    /** Drawable provider that will put a bookmark icon on bookmarked pages. */
    private val drawableProvider =
        object : PdfDrawableProvider() {
            override suspend fun getDrawablesForPage(context: Context, document: PdfDocument, pageIndex: Int): List<PdfDrawable> {
                if (currentBookmarks.any { it.pageIndex == pageIndex }) {
                    // If there's bookmark for the given page index, add our drawable.
                    return listOf(BookmarkDrawable(this@BookmarkHighlightingActivity))
                } else {
                    // Otherwise we draw nothing.
                    return emptyList()
                }
            }
        }

    /** Used to stop the bookmark loading process when closing the activity. */
    private var bookmarkLoadingDisposable: Disposable? = null

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

        currentThumbnailBarMode =
            savedInstanceState?.getString(KEY_THUMBNAIL_BAR_MODE)?.let(ThumbnailBarMode::valueOf)?: initialThumbnailBarMode

        toggleThumbnailBarModeFab =
            FloatingActionButton(this).apply {
                setImageResource(R.drawable.ic_layout_customization)
                val margin = (16 * resources.displayMetrics.density).roundToInt()
                layoutParams =
                    FrameLayout.LayoutParams(
                        FrameLayout.LayoutParams.WRAP_CONTENT,
                        FrameLayout.LayoutParams.WRAP_CONTENT,
                    ).apply {
                        gravity = Gravity.BOTTOM or Gravity.END
                        setMargins(margin, margin, margin, margin)
                    }
                setOnClickListener {
                    currentThumbnailBarMode = nextThumbnailBarMode(currentThumbnailBarMode)
                    applyThumbnailBarMode()
                    currentToast?.cancel()
                    currentToast =
                        Toast.makeText(
                                this@BookmarkHighlightingActivity,
                                getString(
                                    R.string.thumbnail_bar_mode_changed,
                                    getString(currentThumbnailBarMode.labelRes),
                                ),
                                Toast.LENGTH_SHORT,
                            ).also { it.show() }
                }
            }
        findViewById<FrameLayout>(android.R.id.content).addView(toggleThumbnailBarModeFab)
        ViewCompat.setOnApplyWindowInsetsListener(toggleThumbnailBarModeFab) { view, insets ->
            val navigationBarsInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
            (view.layoutParams as? ViewGroup.MarginLayoutParams)?.let { params ->
                params.bottomMargin = (16 * resources.displayMetrics.density).roundToInt() + navigationBarsInsets.bottom
                view.layoutParams = params
            }
            insets
        }
        ViewCompat.requestApplyInsets(toggleThumbnailBarModeFab)

        applyThumbnailBarMode()
    }

    override fun onDocumentLoaded(document: PdfDocument) {
        super.onDocumentLoaded(document)
        // When the document is initially loaded we prepare the first set of bookmarks to be displayed.
        bookmarkLoadingDisposable =
            document.bookmarkProvider.bookmarksAsync.firstOrError().observeOn(AndroidSchedulers.mainThread()).subscribe { bookmarks ->
                    updateBookmarkDrawables(bookmarks)
                }

        // Afterwards we subscribe to be updated whenever the list of bookmarks change.
        document.bookmarkProvider.addBookmarkListener {
            // This is always called on the UI thread so no need for special concurrency handling.
            updateBookmarkDrawables(it)
        }

        applyThumbnailBarMode()
    }

    private fun updateBookmarkDrawables(newBookmarks: List<Bookmark>) {
        currentBookmarks.clear()
        currentBookmarks.addAll(newBookmarks)

        // We need to add and remove the provider so the drawables are correctly redrawn.
        pspdfKitViews.thumbnailBarView?.apply {
            removeDrawableProvider(drawableProvider)
            addDrawableProvider(drawableProvider)
        }
        pspdfKitViews.thumbnailGridView?.apply {
            removeDrawableProvider(drawableProvider)
            addDrawableProvider(drawableProvider)
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putString(KEY_THUMBNAIL_BAR_MODE, currentThumbnailBarMode.name)
    }

    override fun onDestroy() {
        super.onDestroy()
        // Make sure to dispose of this before closing the activity.
        bookmarkLoadingDisposable?.dispose()
    }

    private fun applyThumbnailBarMode() {
        pspdfKitViews.thumbnailBarView?.setThumbnailBarMode(currentThumbnailBarMode)
        toggleThumbnailBarModeFab.contentDescription =
            getString(R.string.toggle_thumbnail_bar_mode, getString(currentThumbnailBarMode.labelRes))
    }

    private fun nextThumbnailBarMode(currentMode: ThumbnailBarMode): ThumbnailBarMode {
        val modes = enumValues<ThumbnailBarMode>()
        return modes[(currentMode.ordinal + 1) % modes.size]
    }

    private val ThumbnailBarMode.labelRes: Int
        get() =
            when (this) {
                ThumbnailBarMode.THUMBNAIL_BAR_MODE_FLOATING -> R.string.thumbnail_bar_mode_floating
                ThumbnailBarMode.THUMBNAIL_BAR_MODE_PINNED -> R.string.thumbnail_bar_mode_pinned
                ThumbnailBarMode.THUMBNAIL_BAR_MODE_SCROLLABLE -> R.string.thumbnail_bar_mode_scrollable
                ThumbnailBarMode.THUMBNAIL_BAR_MODE_NONE -> R.string.thumbnail_bar_mode_none
            }

    private companion object {
        private const val KEY_THUMBNAIL_BAR_MODE = "thumbnail_bar_mode"
    }
}

/**
 * An implementation of [PdfDrawable], which shows an indicator on bookmarked pages.
 */
private class BookmarkDrawable(private val context: Context) : PdfDrawable() {
    // This has to be non null, otherwise this whole example will do nothing.
    private val bookmarkDrawable: Drawable = ContextCompat.getDrawable(context, R.drawable.ic_bookmark_highlight)!!

    /**
     * This will draw our bookmarkDrawable on to the page.
     */
    @SuppressLint("CanvasSize")
    override fun draw(canvas: Canvas) {
        // First we convert our DP constants to their respective pixel sizes.
        val baseSize = BASE_SIZE_DP * context.resources.displayMetrics.density
        val bookmarkSize = BOOKMARK_SIZE_DP * context.resources.displayMetrics.density
        val margin = MARGIN_DP * context.resources.displayMetrics.density

        // We use the canvas size here since that will be the size of the entire page in the thumbnail bar / grid.
        // Based on this size we calculate the real size our bookmark icon will be.
        val ratio = canvas.width / baseSize
        val effectiveBookmarkSize = bookmarkSize * ratio
        val effectiveMargin = margin * ratio

        // Then we place the bookmark in top right edge, with some margin to the right,
        // and moving it up a bit so it sits flush with the page edge.
        bookmarkDrawable.bounds =
            Rect(
                (canvas.width - effectiveBookmarkSize - effectiveMargin).toInt(),
                -effectiveMargin.toInt(),
                (canvas.width - effectiveMargin).toInt(),
                effectiveBookmarkSize.toInt(),
            )

        // Finally we simply draw it onto the page.
        bookmarkDrawable.draw(canvas)
    }

    override fun setAlpha(alpha: Int) {
        // Not required.
    }

    @Deprecated("Deprecated in Java")
    override fun getOpacity(): Int = PixelFormat.TRANSLUCENT

    override fun setColorFilter(colorFilter: ColorFilter?) {
        // Not required.
    }

    companion object {
        /** The width in DP at which the bookmark icon will have it's size, used to scale depending on context. */
        const val BASE_SIZE_DP = 100

        /** The size of the bookmark icon assuming the size of the canvas is BASE_SIZE_DP. */
        const val BOOKMARK_SIZE_DP = 24

        /** The margin to apply to the bookmark icon. */
        const val MARGIN_DP = 8
    }
}

```

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

---

## Related pages

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

