Text Selection

The TextSelectionManager interface contains OnTextSelectionModeChangeListener and OnTextSelectionChangeListener which can be used to listen for text selection changes. The default PdfActivity implementation will display a contextual toolbar, namely TextSelectionToolbar, when the text is long-pressed and the text-selection mode starts. The toolbar provides 5 actions with selected text: highlight, speak, copy to clipboard, share and search.

Registering custom listeners

You can also implement your own TextSelectionManager listeners to react to text selection changes as well as text selection mode changes (entering and exiting text selection mode).

Copy
MyActivity.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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.")
    }
    // You can also return "false" to prevent changes to the current selection state.
    return true
  }
}
Copy
MyActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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.");
      }

      // You can also return "false" to prevent changes to the current selection state.
      return true;
  }
}

This will not override the default behavior, but just register more listeners. If you'd like to have a completely different behavior than showing the toolbar when text selection starts, you need to use PdfFragment inside a custom activity and bind UI with the provided TextSelectionController.

Customize text selection actions

Existing text selection actions can be modified using toolbar.setMenuItems(...). To access the TextSelectionToolbar register the OnContextualToolbarLifecycleListener and configure the actions inside its #onPrepareContextualToolbar method.

Copy
MyActivity.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class MyActivity : PdfActivity(), ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener {

    private lateinit var customTextSelectionAction: ContextualToolbarMenuItem

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

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

        // We 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) {
        // We register a click listener, so we can handle taps on our 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)
    }
}
Copy
MyActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class MyActivity extends PdfActivity
    implements ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener {

    private ContextualToolbarMenuItem customTextSelectionAction;

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

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

        // We 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) {
        // We register a click listener, so we can handle taps on our custom text selection action.
        toolbar.setOnMenuItemClickListener(new ContextualToolbar.OnMenuItemClickListener() {
            @Override public boolean onToolbarMenuItemClick(@NonNull ContextualToolbar toolbar,
                                                            @NonNull ContextualToolbarMenuItem 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);
    }
}

Selecting Text Programatically

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

For example, we'll select the first occurrence of a random string on the page:

Copy
1
2
3
4
5
6
7
// 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))
}
Copy
1
2
3
4
5
6
7
// 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()));
}