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.Menu;
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.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.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);
// We'll enable overlay for all supported annotation types immediately after activity
// creation.
enableOverlayForSupportedAnnotationTypes();
invalidateOptionsMenu();
}
@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);
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
final int itemId = item.getItemId();
if (itemId == R.id.toggle_annotation_overlay) {
if (annotationOverlayEnabled) {
disableOverlayForAllAnnotationTypes();
} else {
enableOverlayForSupportedAnnotationTypes();
}
invalidateOptionsMenu();
return true;
} else if (itemId == 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 (itemId == 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 options to change button text to current state.
invalidateOptionsMenu();
return true;
}
return super.onOptionsItemSelected(item);
}
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 boolean onCreateOptionsMenu(@NonNull Menu menu) {
super.onCreateOptionsMenu(menu);
if (annotationOverlayEnabled) {
menu.add(0, R.id.toggle_annotation_overlay, 0, "Disable annotation overlay");
// Toggling overlay strategy does not make sense when annotation overlay is disabled.
if (currentOverlayRenderingStrategy == AnnotationOverlayRenderStrategy.Strategy.PLATFORM_RENDERING) {
menu.add(0, R.id.toggle_overlay_rendering_strategy, 0, "Use AP stream rendering");
} else {
menu.add(0, R.id.toggle_overlay_rendering_strategy, 0, "Use platform rendering");
}
} else {
menu.add(0, R.id.toggle_annotation_overlay, 0, "Enable annotation overlay");
}
menu.add(0, R.id.fire_low_memory_notification, 0, "Fire low memory notification");
return true;
}
@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.