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

Add toolbars to a custom activity built around PdfFragment.


/*
* Copyright © 2014-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.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.pspdfkit.catalog.R;
import com.pspdfkit.catalog.SdkExample;
import com.pspdfkit.catalog.tasks.ExtractAssetTask;
import com.pspdfkit.configuration.PdfConfiguration;
import com.pspdfkit.configuration.activity.PdfActivityConfiguration;
import com.pspdfkit.ui.PdfFragment;
import com.pspdfkit.ui.annotations.OnAnnotatingModeChangeListener;
import com.pspdfkit.ui.inspector.PropertyInspectorCoordinatorLayout;
import com.pspdfkit.ui.inspector.annotation.AnnotatingInspectorController;
import com.pspdfkit.ui.inspector.annotation.DefaultAnnotationCreationInspectorController;
import com.pspdfkit.ui.inspector.annotation.DefaultAnnotationEditingInspectorController;
import com.pspdfkit.ui.special_mode.controller.AnnotatingController;
import com.pspdfkit.ui.special_mode.controller.TextSelectionController;
import com.pspdfkit.ui.special_mode.manager.TextSelectionManager;
import com.pspdfkit.ui.toolbar.AnnotationToolbar;
import com.pspdfkit.ui.toolbar.ContextualToolbar;
import com.pspdfkit.ui.toolbar.TextSelectionToolbar;
import com.pspdfkit.ui.toolbar.ToolbarCoordinatorLayout;
/**
* This example shows how to use {@link ContextualToolbar}s withing the custom activity that uses
* {@link PdfFragment}.
*/
public class ToolbarsInFragmentExample extends SdkExample {
public ToolbarsInFragmentExample(@NonNull Context context) {
super(context, R.string.toolbarsInFragmentExampleTitle, R.string.toolbarsInFragmentExampleDescription);
}
@Override
public void launchExample(
@NonNull final Context context, @NonNull final PdfActivityConfiguration.Builder configuration) {
ExtractAssetTask.extract(WELCOME_DOC, getTitle(), context, documentFile -> {
final Intent intent = new Intent(context, ToolbarsInFragmentActivity.class);
intent.putExtra(ToolbarsInFragmentActivity.EXTRA_URI, Uri.fromFile(documentFile));
intent.putExtra(
ToolbarsInFragmentActivity.EXTRA_CONFIGURATION,
configuration.build().getConfiguration());
context.startActivity(intent);
});
}
/**
* This example shows how to incorporate {@link ContextualToolbar}s into the custom activity using
* {@link PdfFragment} with all the animations and dragging managed by the {@link
* ToolbarCoordinatorLayout}.
*/
public static class ToolbarsInFragmentActivity extends AppCompatActivity
implements OnAnnotatingModeChangeListener, TextSelectionManager.OnTextSelectionModeChangeListener {
public static final String EXTRA_URI = "ToolbarsInFragmentActivity.DocumentUri";
public static final String EXTRA_CONFIGURATION = "ToolbarsInFragmentActivity.PdfConfiguration";
private PdfFragment fragment;
private ToolbarCoordinatorLayout toolbarCoordinatorLayout;
private Button annotationCreationButton;
private AnnotationToolbar annotationToolbar;
private TextSelectionToolbar textSelectionToolbar;
private boolean annotationCreationActive = false;
private PropertyInspectorCoordinatorLayout inspectorCoordinatorLayout;
private AnnotatingInspectorController annotationEditingInspectorController;
private AnnotatingInspectorController annotationCreationInspectorController;
// Track state for the unified listener
private boolean creationToolbarShown = false;
private boolean editingInspectorBound = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_annotation_toolbar_fragment);
setSupportActionBar(null);
toolbarCoordinatorLayout = findViewById(R.id.toolbarCoordinatorLayout);
annotationToolbar = new AnnotationToolbar(this);
textSelectionToolbar = new TextSelectionToolbar(this);
// Use this if you want to use annotation inspector with annotation creation and editing
// toolbars.
inspectorCoordinatorLayout = findViewById(R.id.inspectorCoordinatorLayout);
annotationEditingInspectorController =
new DefaultAnnotationEditingInspectorController(this, inspectorCoordinatorLayout);
annotationCreationInspectorController =
new DefaultAnnotationCreationInspectorController(this, inspectorCoordinatorLayout);
// The actual document Uri is provided with the launching intent. You can simply change that
// inside the ToolbarsInFragmentExample class.
// This is a check that the example is not accidentally launched without a document Uri.
final Uri uri = getIntent().getParcelableExtra(EXTRA_URI);
if (uri == null) {
showNoDocumentUriDialog();
return;
}
// PdfFragment configuration is provided with the launching intent.
PdfConfiguration configuration = getIntent().getParcelableExtra(EXTRA_CONFIGURATION);
if (configuration == null) {
configuration = new PdfConfiguration.Builder().build();
}
initPdfFragment(uri, configuration);
initAnnotationCreationButton();
}
private void showNoDocumentUriDialog() {
new AlertDialog.Builder(this)
.setTitle("Could not start example.")
.setMessage("No document Uri was provided with the launching intent.")
.setNegativeButton("Leave example", (dialog, which) -> dialog.dismiss())
.setOnDismissListener(dialog -> finish())
.show();
}
private void initAnnotationCreationButton() {
annotationCreationButton = findViewById(R.id.openAnnotationEditing);
annotationCreationButton.setOnClickListener(v -> {
if (annotationCreationActive) {
fragment.exitCurrentlyActiveMode();
} else {
fragment.enterAnnotatingMode();
}
});
updateButtonText();
}
private void initPdfFragment(@NonNull Uri uri, @NonNull PdfConfiguration configuration) {
fragment = (PdfFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = PdfFragment.newInstance(uri, configuration);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
// Use the new unified listener for annotation mode changes
fragment.addOnAnnotatingModeChangeListener(this);
fragment.addOnTextSelectionModeChangeListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
fragment.removeOnAnnotatingModeChangeListener(this);
fragment.removeOnTextSelectionModeChangeListener(this);
}
@Override
public void onEnterAnnotatingMode(@NonNull AnnotatingController controller) {
// Check if we need to show creation toolbar (annotation tool is active)
if (controller.getActiveAnnotationTool() != null && !creationToolbarShown) {
// When entering the annotation creation mode we bind the creation inspector to the provided
// controller.
// Controller handles request for toggling annotation inspector.
annotationCreationInspectorController.bindController(controller);
// When entering the annotation creation mode we bind the toolbar to the provided
// controller, and issue the coordinator layout to animate the toolbar in place.
// Whenever the user presses an action, the toolbar forwards this command to the controller.
// Instead of using the `AnnotationToolbar` you could use a custom UI that operates
// on the controller.
annotationToolbar.bindController(controller);
toolbarCoordinatorLayout.displayContextualToolbar(annotationToolbar, true);
creationToolbarShown = true;
annotationCreationActive = true;
updateButtonText();
}
// Check if we need to bind editing inspector (annotations are selected)
if (controller.hasCurrentlySelectedAnnotations() && !editingInspectorBound) {
annotationEditingInspectorController.bindController(controller);
editingInspectorBound = true;
}
}
@Override
public void onChangeAnnotatingMode(@NonNull AnnotatingController controller) {
// Handle state changes - check if editing mode was entered or exited
if (controller.hasCurrentlySelectedAnnotations() && !editingInspectorBound) {
annotationEditingInspectorController.bindController(controller);
editingInspectorBound = true;
} else if (!controller.hasCurrentlySelectedAnnotations() && editingInspectorBound) {
annotationEditingInspectorController.unbindController();
editingInspectorBound = false;
}
}
@Override
public void onExitAnnotatingMode(@NonNull AnnotatingController controller) {
// Check if creation mode exited (no active tool)
if (controller.getActiveAnnotationTool() == null && creationToolbarShown) {
// Once we're done with editing, unbind the controller from the toolbar, and remove it from
// the toolbar coordinator layout (with animation in this case).
toolbarCoordinatorLayout.removeContextualToolbar(true);
annotationToolbar.unbindController();
annotationCreationInspectorController.unbindController();
creationToolbarShown = false;
annotationCreationActive = false;
updateButtonText();
}
// Check if editing mode exited (no selected annotations)
if (!controller.hasCurrentlySelectedAnnotations() && editingInspectorBound) {
annotationEditingInspectorController.unbindController();
editingInspectorBound = false;
}
}
@Override
public void onEnterTextSelectionMode(@NonNull TextSelectionController controller) {
textSelectionToolbar.bindController(controller);
toolbarCoordinatorLayout.displayContextualToolbar(textSelectionToolbar, true);
}
@Override
public void onExitTextSelectionMode(@NonNull TextSelectionController controller) {
toolbarCoordinatorLayout.removeContextualToolbar(true);
textSelectionToolbar.unbindController();
}
private void updateButtonText() {
annotationCreationButton.setText(annotationCreationActive ? R.string.close_editor : R.string.open_editor);
}
}
}

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