This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/android/samples/annotation-overlay-java.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Annotation Overlay

Display annotations in overlay mode as separate Android Views above the page.


/*
* Copyright © 2018-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.java;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.pspdfkit.annotations.Annotation;
import com.pspdfkit.annotations.AnnotationType;
import com.pspdfkit.catalog.R;
import com.pspdfkit.catalog.SdkExample;
import com.pspdfkit.catalog.tasks.ExtractAssetTask;
import com.pspdfkit.compose.toolbar.state.ToolbarIcon;
import com.pspdfkit.compose.toolbar.state.ToolbarItem;
import com.pspdfkit.compose.toolbar.state.ToolbarItemState;
import com.pspdfkit.configuration.activity.PdfActivityConfiguration;
import com.pspdfkit.ui.PdfActivity;
import com.pspdfkit.ui.PdfActivityIntentBuilder;
import com.pspdfkit.ui.annotations.OnAnnotationSelectedListener;
import com.pspdfkit.ui.rendering.AnnotationOverlayRenderStrategy;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
/** Showcases how to display annotations in overlay mode. */
public class AnnotationOverlayExample extends SdkExample {
public AnnotationOverlayExample(@NonNull final Context context) {
super(context, R.string.annotationOverlayExampleTitle, R.string.annotationOverlayExampleDescription);
}
@Override
public void launchExample(
@NonNull final Context context, @NonNull final PdfActivityConfiguration.Builder configuration) {
// Use custom layout with FAB for per-annotation overlay toggle.
configuration.layout(R.layout.activity_annotation_overlay);
// Extract the document from the assets.
ExtractAssetTask.extract(ANNOTATIONS_EXAMPLE, getTitle(), context, documentFile -> {
// To start the example create a launch intent using the builder.
final Intent intent = PdfActivityIntentBuilder.fromUri(context, Uri.fromFile(documentFile))
.configuration(configuration.build())
.activityClass(AnnotationOverlayActivity.class)
.build();
context.startActivity(intent);
});
}
/** Showcases how to enable overlay mode for annotations. */
public static class AnnotationOverlayActivity extends PdfActivity implements OnAnnotationSelectedListener {
/**
* Holds per-type overlay overrides. When overlay is globally off, these types are
* included in overlay. When overlay is globally on, these types are excluded from overlay.
*/
@NonNull
private final EnumSet<AnnotationType> perTypeOverrides = EnumSet.noneOf(AnnotationType.class);
/** Current strategy used for rendering annotations in overlay. */
@NonNull
private AnnotationOverlayRenderStrategy.Strategy currentOverlayRenderingStrategy =
AnnotationOverlayRenderStrategy.Strategy.AP_STREAM_RENDERING;
/** Flag indicating whether annotation overlay is enabled. */
private boolean annotationOverlayEnabled = false;
/** FAB for toggling overlay on selected annotations. */
private FloatingActionButton overlayFab;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up the FAB for toggling overlay on selected annotation types.
overlayFab = findViewById(R.id.fab_toggle_annotation_overlay);
registerForContextMenu(overlayFab);
overlayFab.setOnClickListener(View::showContextMenu);
// Listen for annotation selection changes to show/hide the FAB.
requirePdfFragment().addOnAnnotationSelectedListener(this);
// We'll set overlay render strategy that just returns currently configured strategy for all
// annotations.
requirePdfFragment().setAnnotationOverlayRenderStrategy(annotation -> currentOverlayRenderingStrategy);
// Add custom toolbar items, computing their labels/visibility from current state.
setToolbarItemsProvider(defaultItems -> {
final List<ToolbarItem> items = new ArrayList<>(defaultItems);
items.add(new ToolbarItem.Button(
"toggle_annotation_overlay",
R.id.toggle_annotation_overlay,
annotationOverlayEnabled ? "Disable annotation overlay" : "Enable annotation overlay",
ToolbarIcon.None.INSTANCE,
new ToolbarItemState(true, false, true),
ToolbarItem.ItemEdge.End,
ToolbarItem.OverflowBehavior.Never));
// Toggling overlay strategy only makes sense when annotation overlay is enabled,
// so the item is hidden otherwise.
final String renderingStrategyTitle =
currentOverlayRenderingStrategy == AnnotationOverlayRenderStrategy.Strategy.PLATFORM_RENDERING
? "Use AP stream rendering"
: "Use platform rendering";
items.add(new ToolbarItem.Button(
"toggle_overlay_rendering_strategy",
R.id.toggle_overlay_rendering_strategy,
renderingStrategyTitle,
ToolbarIcon.None.INSTANCE,
new ToolbarItemState(true, false, annotationOverlayEnabled),
ToolbarItem.ItemEdge.End,
ToolbarItem.OverflowBehavior.Never));
items.add(new ToolbarItem.Button(
"fire_low_memory_notification",
R.id.fire_low_memory_notification,
"Fire low memory notification",
ToolbarIcon.None.INSTANCE,
new ToolbarItemState(true, false, true),
ToolbarItem.ItemEdge.End,
ToolbarItem.OverflowBehavior.Never));
return items;
});
setOnToolbarItemClickListener(id -> {
if (id == R.id.toggle_annotation_overlay) {
if (annotationOverlayEnabled) {
disableOverlayForAllAnnotationTypes();
} else {
enableOverlayForSupportedAnnotationTypes();
}
invalidateToolbarItems();
return true;
} else if (id == R.id.fire_low_memory_notification) {
// We fire low memory notification manually to showcase how annotation overlay
// mode behaves when system is low on memory.
requirePdfFragment().onLowMemory();
return true;
} else if (id == R.id.toggle_overlay_rendering_strategy) {
// Toggle the current overlay rendering strategy.
if (currentOverlayRenderingStrategy
== AnnotationOverlayRenderStrategy.Strategy.AP_STREAM_RENDERING) {
currentOverlayRenderingStrategy = AnnotationOverlayRenderStrategy.Strategy.PLATFORM_RENDERING;
} else {
currentOverlayRenderingStrategy = AnnotationOverlayRenderStrategy.Strategy.AP_STREAM_RENDERING;
}
// Invalidate items to change button text to current state.
invalidateToolbarItems();
return true;
}
return false;
});
// We'll enable overlay for all supported annotation types immediately after activity
// creation.
enableOverlayForSupportedAnnotationTypes();
invalidateToolbarItems();
}
@Override
public void onDestroy() {
super.onDestroy();
requirePdfFragment().removeOnAnnotationSelectedListener(this);
}
@Override
public void onAnnotationSelected(@NonNull Annotation annotation, boolean annotationCreated) {
overlayFab.setVisibility(View.VISIBLE);
}
@Override
public void onAnnotationDeselected(@NonNull Annotation annotation, boolean reselected) {
if (!reselected) {
overlayFab.setVisibility(View.GONE);
}
}
private void disableOverlayForAllAnnotationTypes() {
annotationOverlayEnabled = false;
perTypeOverrides.clear();
applyOverlayTypes();
}
private void enableOverlayForSupportedAnnotationTypes() {
annotationOverlayEnabled = true;
perTypeOverrides.clear();
applyOverlayTypes();
}
private void applyOverlayTypes() {
final EnumSet<AnnotationType> overlayTypes;
if (annotationOverlayEnabled) {
// Start with all types, then remove manually excluded ones.
overlayTypes = EnumSet.allOf(AnnotationType.class);
overlayTypes.removeAll(perTypeOverrides);
} else {
// Start with none, then add manually included ones.
overlayTypes = EnumSet.noneOf(AnnotationType.class);
overlayTypes.addAll(perTypeOverrides);
}
requirePdfFragment().setOverlaidAnnotationTypes(overlayTypes);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
List<Annotation> selectedAnnotations = requirePdfFragment().getSelectedAnnotations();
if (selectedAnnotations.size() != 1) return;
final AnnotationType annotationType = selectedAnnotations.get(0).getType();
// The effective overlay state for this type is: globally on XOR overridden.
final boolean effectivelyOverlaid = annotationOverlayEnabled ^ perTypeOverrides.contains(annotationType);
menu.add(0, R.id.toggle_annotation_overlay, 0, effectivelyOverlaid ? "Disable overlay" : "Enable overlay");
}
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
if (requirePdfFragment().getSelectedAnnotations().size() != 1) {
return super.onContextItemSelected(item);
}
final Annotation annotation =
requirePdfFragment().getSelectedAnnotations().get(0);
final AnnotationType annotationType = annotation.getType();
final int itemId = item.getItemId();
if (itemId == R.id.toggle_annotation_overlay) {
if (perTypeOverrides.contains(annotationType)) {
perTypeOverrides.remove(annotationType);
} else {
perTypeOverrides.add(annotationType);
}
applyOverlayTypes();
return true;
}
return super.onContextItemSelected(item);
}
}
}

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