Selecting text in Android PDF viewer

The TextSelectionManager interface provides two listeners:

These listeners enable you to monitor text selection changes. The default PdfActivity implementation displays a contextual toolbar when text is long-pressed and text selection mode starts. This toolbar is called TextSelectionToolbar and allows you to perform the following five actions with the selected text:

  • Highlight

  • Speak

  • Copy to clipboard

  • Share

  • Search

Registering custom listeners

You can create custom listeners for TextSelectionManager to handle changes in text selection and text selection mode (entering and exiting):

class MyActivity : PdfActivity(), TextSelectionManager.OnTextSelectionChangeListener, TextSelectionManager.OnTextSelectionModeChangeListener {

  const val TAG = "MyActivity.TextSelection"

  override fun onCreate(savedInstanceState: Bundle?) {
    PdfFragment.addOnTextSelectionModeChangeListener(this)
    PdfFragment.addOnTextSelectionChangeListener(this)
  }

  override fun onDestroy(savedInstanceState: Bundle?) {
    PdfFragment.removeOnTextSelectionModeChangeListener(this)
    PdfFragment.removeOnTextSelectionChangeListener(this)
  }

  override fun onEnterTextSelectionMode(controller: TextSelectionController) {
    Log.i(TAG, "Text selection mode has started.")
  }

  override fun onExitTextSelectionMode(controller: TextSelectionController) {
    Log.i(TAG, "Text selection mode has ended.")
  }

  override fun onTextSelectionChange(newTextSelection: TextSelection?, currentTextSelection: TextSelection?): Boolean {
    if (newTextSelection != null) {
      Log.i(TAG, "Selected text was: ${newTextSelection.text}")
    } else {
      Log.i(TAG, "Text selection is cleared.")
    }
    // Return `false` to prevent changes to the current selection state, if needed.
    return true
  }
}
public class MyActivity extends PdfActivity implements TextSelectionManager.OnTextSelectionChangeListener,
    TextSelectionManager.OnTextSelectionModeChangeListener{

  private static final String TAG = "MyActivity.TextSelection";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      getPdfFragment().addOnTextSelectionModeChangeListener(this);
      getPdfFragment().addOnTextSelectionChangeListener(this);
  }

  @Override
  protected void onDestroy(Bundle savedInstanceState) {
      getPdfFragment().removeOnTextSelectionModeChangeListener(this);
      getPdfFragment().removeOnTextSelectionChangeListener(this);
  }

  @Override
  public void onEnterTextSelectionMode(@NonNull TextSelectionController controller) {
      Log.i(TAG, "Text selection mode has started.");
  }

  @Override
  public void onExitTextSelectionMode(@NonNull TextSelectionController controller) {
      Log.i(TAG, "Text selection mode has ended.");
  }

  @Override
  public boolean onTextSelectionChange(@Nullable TextSelection newTextSelection, @Nullable TextSelection currentTextSelection) {
      if (newTextSelection != null) {
          Log.i(TAG, String.format("Selected text was: %s", newTextSelection.text));
      } else {
          Log.i(TAG, "Text selection is cleared.");
      }

      // Return `false` to prevent changes to the current selection state, if needed.
      return true;
  }
}

By implementing these listeners, you can add custom reactions to text selection events.

This setup doesn’t override the default behavior — it only adds additional listeners. If you need to completely change the behavior (e.g. replacing the toolbar with a custom user interface), use PdfFragment in a custom activity and bind it to the TextSelectionController.

Customize text selection actions

You can modify existing text selection actions or add new ones using toolbar.setMenuItems(...). To access the TextSelectionToolbar, register the OnContextualToolbarLifecycleListener and configure actions in its #onPrepareContextualToolbar method:

class MyActivity : PdfActivity(), ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener {

    private lateinit var customTextSelectionAction: ContextualToolbarMenuItem

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

        // Register the activity as a callback for contextual toolbar changes.
        // It will be called once the `TextSelectionToolbar` is going to be presented.
        setOnContextualToolbarLifecycleListener(this)

        // Create a custom menu item that will be shown inside the text selection toolbar.
        customTextSelectionAction = ContextualToolbarMenuItem.create(
            this,
            R.id.custom_text_action,
            AppCompatDrawableManager.get().getDrawable(this, R.drawable.ic_my_action),
            "Custom text action",
            Color.WHITE,
            Color.RED,
            false)
    }

    override fun onPrepareContextualToolbar(toolbar: ContextualToolbar) {
        // Add the custom action once the selection toolbar is being prepared.
        // At this point, you could also remove undesired actions from the toolbar.
        if (toolbar is TextSelectionToolbar) {
            val menuItems = toolbar.getMenuItems()
            if (!menuItems.contains(customTextSelectionAction)) {
                menuItems.add(customTextSelectionAction)
                toolbar.setMenuItems(menuItems)
            }
        }
    }

    override fun onDisplayContextualToolbar(toolbar: ContextualToolbar) {
        // Register a click listener to handle taps on the custom text selection action.
        toolbar.setOnMenuItemClickListener { toolbar, menuItem ->
            var handled = false

            if (menuItem.id == R.id.custom_text_action) {
                handled = true
                Toast.makeText(this@MyActivity, "Text selection action triggered!", Toast.LENGTH_SHORT)
                    .show()
            }

            handled
        }
    }

    override fun onRemoveContextualToolbar(toolbar: ContextualToolbar) {
        toolbar.setOnMenuItemClickListener(null)
    }
}
public class MyActivity extends PdfActivity
    implements ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener {

    private ContextualToolbarMenuItem customTextSelectionAction;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Register the activity as a callback for contextual toolbar changes.
        // It will be called once the `TextSelectionToolbar` is going to be presented.
        setOnContextualToolbarLifecycleListener(this);

        // Create a custom menu item that will be shown inside the text selection toolbar.
        customTextSelectionAction = ContextualToolbarMenuItem.create(
            this,
            R.id.custom_text_action,
            AppCompatDrawableManager.get().getDrawable(this, R.drawable.ic_my_action),
            "Custom text action",
            Color.WHITE,
            Color.RED,
            false
        );
    }

    @Override public void onPrepareContextualToolbar(@NonNull ContextualToolbar toolbar) {
        // Add the custom action once the selection toolbar is being prepared.
        // At this point, you could also remove undesired actions from the toolbar.
        if (toolbar instanceof TextSelectionToolbar) {
            final List<ContextualToolbarMenuItem> menuItems = toolbar.getMenuItems();
            if (!menuItems.contains(customTextSelectionAction)) {
                menuItems.add(customTextSelectionAction);
                toolbar.setMenuItems(menuItems);
            }
        }
    }

    @Override public void onDisplayContextualToolbar(@NonNull ContextualToolbar toolbar) {
        // Register a click listener to handle taps on the custom text selection action.
        toolbar.setOnMenuItemClickListener((contextualToolbar, menuItem) -> {
            boolean handled = false;

            if (menuItem.getId() == R.id.custom_text_action) {
                handled = true;
                Toast.makeText(MyActivity.this, "Text selection action triggered!", Toast.LENGTH_SHORT)
                    .show();
            }

            return handled;
        });
    }

    @Override public void onRemoveContextualToolbar(@NonNull ContextualToolbar toolbar) {
        toolbar.setOnMenuItemClickListener(null);
    }
}

This approach allows you to add custom actions to the toolbar or remove existing ones when the toolbar is prepared.

Selecting text programmatically

You can programmatically select text using the PdfFragment#enterTextSelectionMode method and specifying the text range to be selected. You can retrieve the text of the current page by calling the PdfDocument#getPageText method.

For example, to select the first occurrence of a string on the page, use the following code:

// Search for the position of text that should be selected.
val textToSelect = "text to select"
val textIndexOnPage = document.getPageText(pageIndex).indexOf(textToSelect)
if (textIndexOnPage >= 0) {
    // Select the text.
    fragment.enterTextSelectionMode(pageIndex, Range(textIndexOnPage, textToSelect.length))
}
// Search for the position of text that should be selected.
String textToSelect = "text to select";
int textIndexOnPage = document.getPageText(pageIndex).indexOf(textToSelect);
if (textIndexOnPage >= 0) {
    // Select the text.
    fragment.enterTextSelectionMode(pageIndex, new Range(textIndexOnPage, textToSelect.length()));
}

Alternatively, you can select text by providing a list of rectangles, and the text beneath these rectangles will be selected. Use the TextSelectionRectangles object, which is created in one of the following ways:

  • Provide a list of rectangles (no markup padding applied).

  • Provide a list of rectangles with markup padding.

fragment.enterTextSelectionMode(pageIndex, TextSelectionRectangles(rectangles, markupRectangles))
fragment.enterTextSelectionMode(pageIndex, new TextSelectionRectangles(rectangles, markupRectangles));

Nutrient Android SDK throws an IllegalStateException in the following scenarios:

  • Invalid parameters are provided.

  • The text range exceeds the available text on the page.

  • No text exists beneath the specified rectangles.