> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/android/ui-customization/custom-tool.md).

# Creating a custom PDF viewer tool in Android

Learn how to create a custom rectangular cloudy annotation tool for PDFViewCtrl with this comprehensive guide. Find sample code and step-by-step instructions here! The Apryse Android SDK streamlines s

{% hint style="info" %}
The sample code for this guide can be found at our [GitHub repository](https://github.com/ApryseSDK/pdftron-android-samples/tree/master/CustomToolSample/).
{% endhint %}

## Overview

The tools package provides several base classes that can be extended to create and add custom tools to the viewer. Click [here for a complete list of tools](/android/ui-customization/tool-subclasses.md).

In this guide, we will create a custom rectangular cloudy annotation tool for either [PDFViewCtrl](/android/open-save-document/open/view.md) or [PdfViewCtrlTabHostFragment2](/android/open-save-document/open/fragment.md). It is recommended to read the following articles before continuing this guide:

* [Show a document in a Fragment](/android/open-save-document/open/fragment.md)
* [Customize viewer](/android/viewer/fragment-config.md)
* [Customize ToolManager](/android/annotation/toolmanager-config.md)

## Step 1: Pick a base tool class to inherit

From this [tool hiearchy list](/android/ui-customization/tool-subclasses.md), find a base tool class to extend. For example, here are some of the more commonly used base tool classes:

| Tool                                                                                                                   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`TextMarkupCreate`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/TextMarkupCreate.html) | Creates a text markup annotation. Derive from this class to create annotation on text. Override \[`createMarkup`]\(<https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/TextMarkupCreate.html#createMarkup(PDFDoc>, com.pdftron.pdf.Rect)) to create an [`Annot`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/Annot.html) object.                                                                                |
| [`RectCreate`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/RectCreate.html)             | Draws and creates a rectangle annotation. Derive from this class to draw rectangles, for example, checkbox form field. Override \[`createMarkup`]\(<https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/RectCreate.html#createMarkup(PDFDoc>, Rect)) to create an [`Annot`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/Annot.html) object.                                                                      |
| [`OvalCreate`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/OvalCreate.html)             | Draws and creates an ellipse annotation. Derive from this class if draw ellipses. Override \[`createMarkup`]\(<https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/OvalCreate.html#createMarkup(PDFDoc>, Rect)) to create an [`Annot`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/Annot.html) object.                                                                                                           |
| [`SimpleShapeCreate`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/LineCreate.html)      | Creates various shape annotations such as rectangle, ellipse, ink line and [more ](/android/ui-customization/tool-subclasses.md). Use this class if none of the above works for you. Override \[`createMarkup`]\(<https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/SimpleShapeCreate.html#createMarkup(PDFDoc>, Rect)) to create an [`Annot`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/Annot.html) object. |

For our custom rectangular cloudy annotation tool, we'll be creating a class called `CustomTool` that inherits from `RectCreate`.

## Step 2: Override the base class methods

1. In the `CustomTool` class, override the [`getToolMode()`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/Tool.html#getToolMode\(\)) method. This method must return a custom tool mode, which can be created by calling [`ToolManager.ToolMode.addNewMode(int)`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/ToolManager.ToolMode.html#addNewMode\(int\)) and specifying the custom tool's annotation type.
2. Afterwards, override the feature specific methods and implement the desired custom behavior. Add `@Keep` so the tool can work properly in release mode. For example here is a custom tool that handles creating rectangular cloudy annotations:

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
import com.pdftron.pdf.utils.Utils;
import com.pdftron.pdf.Point;
import com.pdftron.pdf.Rect;
// ...

/**
* This class is to create a rectangular cloudy annotation.
*/
@Keep
public class CustomTool extends RectCreate {

    // Since this tool creates polygon annotation, use Annot.e_Polygon as parameter.
    public static ToolManager.ToolModeBase MODE = 
            ToolManager.ToolMode.addNewMode(Annot.e_Polygon);

    public CustomTool(@NonNull PDFViewCtrl ctrl) {
        super(ctrl);
    }

    @Override
    public ToolManager.ToolModeBase getToolMode() {
        return MODE;
    }

    @Override
    protected Annot createMarkup(PDFDoc doc, Rect bbox) throws PDFNetException {
        Polygon poly = new Polygon(Polygon.create(doc, Annot.e_Polygon, bbox));
        ColorPt color = Utils.color2ColorPt(Color.RED);
        poly.setColor(color, 3);
        poly.setVertex(0, new Point(bbox.getX1(), bbox.getY1()));
        poly.setVertex(1, new Point(bbox.getX1(), bbox.getY2()));
        poly.setVertex(2, new Point(bbox.getX2(), bbox.getY2()));
        poly.setVertex(3, new Point(bbox.getX2(), bbox.getY1()));
        poly.setIntentName(PolyLine.e_PolygonCloud);
        poly.setBorderEffect(Markup.e_Cloudy);
        poly.setBorderEffectIntensity(2.0);
        poly.setRect(bbox);

        return poly;
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
import com.pdftron.pdf.utils.Utils
import com.pdftron.pdf.Point
import com.pdftron.pdf.Rect
// ...

/**
* This class is to create a rectangular cloudy annotation.
*/
@Keep
class CustomTool(ctrl: PDFViewCtrl) : RectCreate(ctrl) {

companion object {
    // Since this tool creates polygon annotation, use Annot.e_Polygon as parameter.
    var MODE: ToolManager.ToolModeBase = ToolManager.ToolMode.addNewMode(Annot.e_Polygon)
}

override fun getToolMode(): ToolManager.ToolModeBase {
    return MODE
}

override fun createMarkup(doc: PDFDoc, bbox: Rect): Annot {
    val poly = Polygon(Polygon.create(doc, Annot.e_Polygon, bbox))
    val color = Utils.color2ColorPt(Color.RED)
    poly.setColor(color!!, 3)
    poly.setVertex(0, Point(bbox.x1, bbox.y1))
    poly.setVertex(1, Point(bbox.x1, bbox.y2))
    poly.setVertex(2, Point(bbox.x2, bbox.y2))
    poly.setVertex(3, Point(bbox.x2, bbox.y1))
    poly.intentName = PolyLine.e_PolygonCloud
    poly.borderEffect = Markup.e_Cloudy
    poly.borderEffectIntensity = 2.0
    poly.rect = bbox

    return poly
}
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Step 3: Register the custom tool in ToolManager

All tools are controlled by an instance of [`ToolManager`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/ToolManager.html) and it will need to know about the new custom tool before the tool can be used in the viewer.

* A `PdfViewCtrlTabHostFragment2` contains an internal reference to `ToolManager`. A custom tool can be added to this internal `ToolManager` by using the [`ToolManagerBuilder`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/config/ToolManagerBuilder.html) class. A `ToolManagerBuilder` object is passed to an instance of [`ViewerConfig`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/config/ViewerConfig.html) and used to initialize the viewer with the custom tool. The following method can be called in an activity to add a custom tool to a `PdfViewCtrlTabHostFragment2`:

### Option 1: Register using PdfViewCtrlTabHostFragment2

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
// Add a custom tool to ViewerConfig and use it to initialize a PdfViewCtrlTabHostFragment2
public PdfViewCtrlTabHostFragment2 addCustomTool(@NonNull Context context, @NonNull Uri fileUri) {
    // Create the ToolManagerBuilder builder and add our custom tool
    ToolManagerBuilder toolManagerBuilder = ToolManagerBuilder
            .from()
            .addCustomizedTool(CustomTool.MODE, CustomTool.class);
    // Add the ToolManagerBuilder builder to a ViewerConfig, that will
    // be used to initialize PdfViewCtrlTabHostFragment2
    ViewerConfig config = new ViewerConfig.Builder()
            .toolManagerBuilder(toolManagerBuilder)
            .build();
    // Create the custom PdfViewCtrlTabHostFragment2 using the custom ViewerConfig object
    return ViewerBuilder2.withUri(fileUri)
            .usingConfig(config)
            .build(context);
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
// Add a custom tool to ViewerConfig and use it to initialize a PdfViewCtrlTabHostFragment2
fun addCustomTool(context: Context, fileUri: Uri): PdfViewCtrlTabHostFragment2? {
    // Create the ToolManagerBuilder builder and add our custom tool
    val toolManagerBuilder = ToolManagerBuilder
            .from()
            .addCustomizedTool(CustomTool.MODE, CustomTool::class.java)
    // Add the ToolManagerBuilder builder to a ViewerConfig, that will
    // be used to initialize PdfViewCtrlTabHostFragment2
    val config = ViewerConfig.Builder()
            .toolManagerBuilder(toolManagerBuilder)
            .build()
    // Create the custom PdfViewCtrlTabHostFragment2 using the custom ViewerConfig object
    return ViewerBuilder2.withUri(fileUri)
            .usingConfig(config)
            .build(context)
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

* Alternatively if `PDFViewCtrl` is used and set up with a `ToolManager`, you can simply add the custom tool directly to `ToolManager` by calling:

### Option 2: Register using PDFViewCtrl

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
// Add a custom tool to ToolManager using PDFViewCtrl
public void addCustomTool(@NonNull ToolManager toolManager, @NonNull PDFViewCtrl pdfViewCtrl) {
    // Create our custom tool
    Tool customTool = new CustomTool(pdfViewCtrl);
    // Then add it to ToolManager
    toolManager.addCustomizedTool(customTool);
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
// Add a custom tool to ToolManager using PDFViewCtrl
fun addCustomTool(toolManager: ToolManager, pdfViewCtrl: PDFViewCtrl) {
    // Create our custom tool
    val customTool = CustomTool(pdfViewCtrl)
    // Then add it to ToolManager
    toolManager.addCustomizedTool(customTool)
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
You can learn more about setting up `PDFViewCtrl` with `ToolManager` in the [ToolManager customization guide ](/android/annotation/toolmanager-config.md).
{% endhint %}

## Step 4: Use the custom tool

To use the custom tool, set it to an instance of `ToolManager` as follows:

*

### Option 1: Using PdfViewCtrlTabHostFragment2

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
public void useCustomTool(@NonNull PdfViewCtrlTabHostFragment2 fragment) {
    // Create our custom tool
    ToolManager toolManager = fragment.getCurrentPdfViewCtrlFragment().getToolManager();
    ToolManager.Tool customTool = toolManager.createTool(CustomTool.MODE, toolManager.getTool());
    // Then set it in ToolManager
    toolManager.setTool(customTool);
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
fun useCustomTool(fragment: PdfViewCtrlTabHostFragment2) {
    // Create our custom tool
    val toolManager = fragment.currentPdfViewCtrlFragment!!.toolManager
    val customTool = toolManager!!.createTool(CustomTool.MODE, toolManager.tool)
    // Then set it in ToolManager
    toolManager.tool = customTool
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

*

### Option 2: Using PDFViewCtrl

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
public void useCustomTool(@NonNull ToolManager toolManager, @NonNull PDFViewCtrl pdfViewCtrl) {
    // Create our custom tool
    Tool customTool = new CustomTool(pdfViewCtrl);
    // Then add it to ToolManager
    toolManager.addCustomizedTool(customTool);
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
fun useCustomTool(fragment: PdfViewCtrlTabHostFragment2) {
    // Create our custom tool
    val toolManager = fragment.currentPdfViewCtrlFragment!!.toolManager
    val customTool = toolManager!!.createTool(CustomTool.MODE, toolManager.tool)
    // Then set it in ToolManager
    toolManager.tool = customTool
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Now, when using the custom tool you will see the following:

![](https://226546913-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0QItsdFBmuuL9ezHimHy%2Fuploads%2Fgit-blob-127308cb260336799b8eb01cfda9efa806779528%2F4e280139774da2e6cd0efec7eeb76631bc6a6d79-877x957.png?alt=media)

## Step 5: Switch to another tool during motion events

You will be able to switch tool modes within the same tool class in response to a motion event, such as [`onDown(MotionEvent)`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/Tool.html#onDown\(android.view.MotionEvent\)), [`onDoubleTap(MotionEvent)`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/Tool.html#onDoubleTap\(android.view.MotionEvent\)) and so on.

In gesture event functions, if one tool switches to another tool, that motion event will continue to be executed in the next tool ([see tools overview for more information](/android/annotation/tools.md)). So if the custom tool wants to switch to another tool during a motion event, you can set the next tool mode by calling [`Tool.safeSetNextToolMode(ToolMode)`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/Tool.html#safeSetNextToolMode\(com.pdftron.pdf.tools.ToolManager.ToolModeBase\)).

For example, let's override `onSingleTapConfirmed` in `CustomTool.java`, and set the next tool to be [`TextHighlightCreate`](https://sdk.apryse.com/api/android/javadoc/reference/com/pdftron/pdf/tools/TextHighlightCreate.html):

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
    mNextToolMode = safeSetNextToolMode(ToolManager.ToolMode.TEXT_HIGHLIGHT);
    return false;
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
fun onSingleTapConfirmed(e: MotionEvent): Boolean {
    mNextToolMode = safeSetNextToolMode(ToolManager.ToolMode.TEXT_HIGHLIGHT)
    return false
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Now in response to a single tap while using your custom tool, it will switch to the `TextHighlightCreate` tool.

{% hint style="info" %}
If you need to save the `ToolMode` and retrieve it at a later time, you can call `toString()` on the `ToolMode` object and retrieve the instance later by calling `ToolMode.valueOf(String)`.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/android/ui-customization/custom-tool.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
