Custom text editors are views that are not
[`EditText`](https://developer.android.com/reference/kotlin/android/widget/EditText) components or
[`WebView`](https://developer.android.com/reference/kotlin/android/webkit/WebView) text widgets but
nevertheless support text input by implementing the
[`onCreateInputConnection()`](https://developer.android.com/reference/kotlin/android/view/View#oncreateinputconnection)
callback, which is called when a view is focused and the system requests an
[`InputConnection`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputConnection)
for the view.

A call to
[`onCheckIsTextEditor()`](https://developer.android.com/reference/kotlin/android/view/View#oncheckistexteditor)
from a custom text editor should return `true`.

## Support stylus handwriting in custom text editors

Android 14 (API level 34) and higher support stylus input in standard Android
text entry components by default (see [Stylus input in text
fields](https://developer.android.com/develop/ui/views/touch-and-input/stylus-input/stylus-input-in-text-fields)).
However, custom text entry fields (or editors) require additional development.

To create a custom text editor, do the following:

1. Enable handwriting initiation
2. Declare handwriting support
3. Support handwriting gestures (select, delete, insert, and so on)
4. Provide cursor location and other position data to the IME
5. Show the stylus handwriting hover icon

## Enable handwriting initiation

If a view consists solely of a single text editor, the view system can
automatically initiate stylus handwriting for the view. Otherwise, the view must
implement its own handwriting initiation logic.

### Automatic handwriting initiation

If a view displays a single text editor and no other content, the view can opt
into the view system's automatic handwriting initiation by calling
[`setAutoHandwritingEnabled(true)`](https://developer.android.com/reference/kotlin/android/view/View#setautohandwritingenabled).

With auto handwriting enabled, stylus motion starting anywhere within the view's
handwriting bounds automatically initiates handwriting mode. The input method
editor ([IME](https://developer.android.com/develop/ui/views/touch-and-input/creating-input-method)) receives
the stylus motion events and commits the recognized text.
![Input field with surrounding rectangle indicating the bounds for detection of stylus motion events.](https://developer.android.com/static/images/develop/ui/compose/touch-input/stylus-input/shared/edittext_handwriting_bounds.png) **Figure 1.** Handwriting within the bounds of a `EditText` field.

### Custom handwriting initiation

If a view contains multiple text editors or content in addition to a single text
editor, the view must implement its own handwriting initiation logic as follows:

1. Opt out of the view system's automatic handwriting initiation by calling
   [`setAutoHandwritingEnabled(false)`](https://developer.android.com/reference/kotlin/android/view/View#setautohandwritingenabled).

2. Keep track of all text editors that are visible within the view.

3. Monitor motion events received by the view in
   [`dispatchTouchEvent()`](https://developer.android.com/reference/kotlin/android/view/View#dispatchtouchevent).

   - When stylus motion occurs within a text editor's handwriting bounds,
     focus the text editor (if not already focused).

   - If the editor was not already focused, restart the editor's IME with new
     contents by calling
     [`InputMethodManager#restartInput()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputMethodManager#restartinput).

   - Start the stylus handwriting session by calling
     [`InputMethodManager#startStylusHandwriting()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputMethodManager#startstylushandwriting).

| **Note:** By default, the handwriting bounds of an `EditText` include 40 dp of vertical padding and 10 dp of horizontal padding (see figure 1). Match these bounds in custom editor views.

If a text editor is inside a scrollable view, stylus movement within the
editor's handwriting bounds should be considered handwriting, not scrolling. Use
[`ViewParent#requestDisallowInterceptTouchEvent()`](https://developer.android.com/reference/kotlin/android/view/ViewParent#requestdisallowintercepttouchevent)
to prevent a scrollable ancestor view from intercepting touch events from a text
editor.

### API details

- [**`MotionEvent#getToolType()`**](https://developer.android.com/reference/kotlin/android/view/MotionEvent#gettooltype)
  --- Indicates whether the `MotionEvent` is from a stylus, in which case
  the return value is
  [`TOOL_TYPE_STYLUS`](https://developer.android.com/reference/kotlin/android/view/MotionEvent#tool_type_stylus)
  or
  [`TOOL_TYPE_ERASER`](https://developer.android.com/reference/kotlin/android/view/MotionEvent#tool_type_eraser).

  | **Note:** When the user presses the eraser button on a stylus and then motions with the stylus, the motion event return type is `TOOL_TYPE_ERASER`. Start handwriting mode and let the IME determine how to recognize the stylus movement.
- [**`InputMethodManager#isStylusHandwritingAvailable()`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputMethodManager#isstylushandwritingavailable)
  --- Indicates whether the IME supports stylus handwriting. Call this
  method before every call to `InputMethodManager#startStylusHandwriting()`
  since the handwriting availability may have changed.

- [**`InputMethodManager#startStylusHandwriting()`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputMethodManager#startstylushandwriting)
  --- Causes the IME to enter handwriting mode. An
  [`ACTION_CANCEL`](https://developer.android.com/reference/kotlin/android/view/MotionEvent#action_cancel)
  motion event is dispatched to the app to cancel the current gesture. Stylus
  motion events are no longer dispatched to the app.

  Stylus motion events of the current gesture that were already dispatched to
  the app are forwarded to the IME. The IME is required to show a stylus ink
  window through which the IME receives all following `MotionEvent` objects.
  The IME commits recognized handwriting text using the
  [`InputConnection`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputConnection)
  APIs.

  If the IME can't enter handwriting mode, this method call is a no-op.
  | **Note:** You can successfully call `startStylusHandwriting()` only when the view argument has focus and an active input connection. The window containing the view must also have focus.

## Declare handwriting support

When filling in the
[`EditorInfo`](https://developer.android.com/reference/kotlin/android/view/inputmethod/EditorInfo) argument
of
[`View#onCreateInputConnection(EditorInfo)`](https://developer.android.com/reference/kotlin/android/view/View#oncreateinputconnection) call
[`setStylusHandwritingEnabled()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/EditorInfo#setstylushandwritingenabled) to inform the IME that the text editor supports handwriting.
Declare supported gestures with
[`setSupportedHandwritingGestures()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/EditorInfo#setsupportedhandwritinggestures)
and
[`setSupportedHandwritingGesturePreviews()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/EditorInfo#setsupportedhandwritinggesturepreviews).

## Support handwriting gestures

IMEs can support various handwriting gestures, such as circling text to select
it or scribbling over text to delete it.
Your browser doesn't support the video tag. **Figure 2.** Circle to select text. Your browser doesn't support the video tag. **Figure 3.** Scribble to delete text.

Custom editors implement
[`InputConnection#performHandwritingGesture()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputConnection#performhandwritinggesture)
and
[`InputConnection#previewHandwritingGesture()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputConnection#previewhandwritinggesture)
to support different
[`HandwritingGesture`](https://developer.android.com/reference/kotlin/android/view/inputmethod/HandwritingGesture)
types, such as
[`SelectGesture`](https://developer.android.com/reference/kotlin/android/view/inputmethod/SelectGesture),
[`DeleteGesture`](https://developer.android.com/reference/kotlin/android/view/inputmethod/DeleteGesture), and
[`InsertGesture`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InsertGesture).

Declare supported handwriting gestures when filling in the `EditorInfo` argument
of `View#onCreateInputConnection(EditorInfo)` (see the [Declare handwriting
support](https://developer.android.com/develop/ui/views/touch-and-input/stylus-input/custom-text-editors#declare_handwriting_support) section).

### API details

- [**`InputConnection#performHandwritingGesture(HandwritingGesture, Executor,
  IntConsumer)`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputConnection#performhandwritinggesture)
  --- Implements gestures. The `HandwritingGesture` argument contains
  location information which you can use to determine where in the text to
  perform the gesture. For example, `SelectGesture` provides a
  [`RectF`](https://developer.android.com/reference/kotlin/android/graphics/RectF) object that
  specifies the selected text range, and `InsertGesture` provides a
  [`PointF`](https://developer.android.com/reference/kotlin/android/graphics/PointF) object that
  specifies the text offset at which to insert text.

  Use the [`Executor`](https://developer.android.com/reference/kotlin/java/util/concurrent/Executor) and
  [`IntConsumer`](https://developer.android.com/reference/kotlin/java/util/function/IntConsumer) parameters
  to send back the result of the operation. When both the executor and
  consumer arguments are provided, use the executor to call
  [`IntConsumer#accept()`](https://developer.android.com/reference/kotlin/java/util/function/IntConsumer#accept),
  for example:  


      executor.execute { consumer.accept(HANDWRITING_GESTURE_RESULT_SUCCESS) }

- [**`HandwritingGesture#getFallbackText()`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/HandwritingGesture#getfallbacktext)
  --- Provides fallback text the IME commits at the cursor position if no
  applicable text is beneath the area of a handwriting gesture.

  Sometimes the IME is not able to determine whether a stylus gesture is
  intended to perform a gesture operation or to handwrite text. A custom text
  editor is responsible for determining the user's intention and performing
  the appropriate action (depending on context) at the gesture location.

  For example, if the IME cannot ascertain whether the user meant to draw a
  downward caret ⋁ to perform an insert space gesture or to handwrite the
  letter "v," the IME can send an `InsertGesture` with fallback text "v".

  The editor should first try to perform the insert space gesture. If the
  gesture cannot be performed (for example, there is no text at the location
  specified), the editor should fall back to inserting "v" at the cursor
  position.
- [**`InputConnection#previewHandwritingGesture(PreviewableHandwritingGesture,
  CancellationSignal)`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputConnection#previewhandwritinggesture)
  --- Previews an ongoing gesture. For example, as the user begins to draw
  a circle around some text, a live preview of the resulting selection can be
  shown and continuously updated as the user continues drawing. Only certain
  gesture types are previewable (see
  [`PreviewableHandwritingGesture`](https://developer.android.com/reference/kotlin/android/view/inputmethod/PreviewableHandwritingGesture)).

  The `CancellationSignal` parameter can be used by the IME to cancel the
  preview. If other events disrupt the preview (for example, text is changed
  programmatically or new `InputConnection` commands occur), the custom editor
  can cancel the preview.

  Preview gestures are for display only and shouldn't change the editor's
  state. For example, a `SelectGesture` preview hides the editor's current
  selection range and highlights the gesture preview range. But once the
  preview is canceled, the editor should restore its previous selection range.

## Provide cursor location and other position data

In handwriting mode, the IME can request cursor location and other position data
using
[`InputConnection#requestCursorUpdates()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputConnection#requestcursorupdates).
The custom editor responds with a call to
[`InputMethodManager#updateCursorAnchorInfo(View,
CursorAnchorInfo)`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputMethodManager#updatecursoranchorinfo).
The data in
[`CursorAnchorInfo`](https://developer.android.com/reference/kotlin/android/view/inputmethod/CursorAnchorInfo)
relevant to stylus handwriting is provided through the following
[`CursorAnchorInfo.Builder`](https://developer.android.com/reference/kotlin/android/view/inputmethod/CursorAnchorInfo.Builder)
methods:

- [**`setInsertionMarkerLocation()`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/CursorAnchorInfo.Builder#setinsertionmarkerlocation) --- Sets the location of the cursor. The IME uses the value to animate handwriting ink to the cursor location.
- [**`setEditorBoundsInfo()`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/CursorAnchorInfo.Builder#seteditorboundsinfo) --- Sets the editor's bounds and the handwriting bounds. The IME uses this data to position the IME's handwriting toolbar on screen.
- [**`addVisibleLineBounds()`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/CursorAnchorInfo.Builder#addvisiblelinebounds) --- Sets the bounds of all visible (or partially visible) text lines of the editor. The IME uses the line bounds to improve accuracy in recognizing handwriting gestures.
- [**`setTextAppearanceInfo()`**](https://developer.android.com/reference/kotlin/android/view/inputmethod/CursorAnchorInfo.Builder#settextappearanceinfo) --- Sets the text appearance with information derived from the text input field. The IME uses the information to style the handwriting ink.

## Show the stylus handwriting hover icon

Display the stylus handwriting hover icon when the stylus hovers over the
handwriting bounds of your custom text editor and the selected IME supports
stylus handwriting
([`InputMethodManager#isStylusHandwritingAvailable()`](https://developer.android.com/reference/kotlin/android/view/inputmethod/InputMethodManager#isstylushandwritingavailable)).

Override
[`View#onResolvePointerIcon()`](https://developer.android.com/reference/kotlin/android/view/View#onresolvepointericon)
to get a hover icon for stylus handwriting. In the override, call
[`PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING)`](https://developer.android.com/reference/kotlin/android/view/PointerIcon#getsystemicon)
to access the system's stylus handwriting hover icon.

## Additional resources

- [Stylus input in text fields](https://developer.android.com/develop/ui/views/touch-and-input/stylus-input/stylus-input-in-text-fields)