When users draw, write, or interact with an app using a stylus, they sometimes touch the screen with the palm of their hands. The touch event might be reported to your app before the system recognizes and dismisses the event as an accidental palm touch.
Your app must identify extraneous touch events and ignore them. Android 13 and higher API levels indicate palm touches differently from all other API levels.
Results
Your app is able to identify and reject palm touches for multi-pointer events on Android 13 and higher API levels and for single-pointer events on all API levels.
Identify and ignore palm touches
Android cancels a palm touch by dispatching a MotionEvent object to your
app.
Examine
MotionEventobjects dispatched to your app. Use theMotionEventAPIs to determine event properties (actions and flags):- Single-pointer events — Check for
ACTION_CANCEL. On Android 13 and higher, also check forFLAG_CANCELED. - Multi-pointer events — On Android 13 and higher, check for
ACTION_POINTER_UPandFLAG_CANCELED.
- Single-pointer events — Check for
Ignore motion events that have the
ACTION_CANCELandACTION_POINTER_UP/FLAG_CANCELEDproperties.
1. Acquire motion event objects
Add an OnTouchListener to your app:
Kotlin
val myView = findViewById<View>(R.id.myView).apply { setOnTouchListener { view, event -> // Process motion event. } }
Java
View myView = findViewById(R.id.myView); myView.setOnTouchListener( (view, event) -> { // Process motion event. });
2. Determine the event action and flags
Check for ACTION_CANCEL, which indicates a single-pointer event on all API
levels. On Android 13 and higher, check ACTION_POINTER_UP for FLAG_CANCELED.
Kotlin
val myView = findViewById<View>(R.id.myView).apply { setOnTouchListener { view, event -> when (event.actionMasked) { MotionEvent.ACTION_CANCEL -> { //Process canceled single-pointer motion event for all SDK versions. } MotionEvent.ACTION_POINTER_UP -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && (event.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) { //Process canceled multi-pointer motion event for Android 13 and higher. } } } true } }
Java
View myView = findViewById(R.id.myView); myView.setOnTouchListener( (view, event) -> { switch (event.getActionMasked()) { case MotionEvent.ACTION_CANCEL: // Process canceled single-pointer motion event for all SDK versions. case MotionEvent.ACTION_UP: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && (event.getFlags() & MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) { //Process canceled multi-pointer motion event for Android 13 and higher. } } return true; });
3. Undo the gesture
After you've identified a palm touch, you can undo the onscreen effects of the gesture.
Your app must keep a history of user actions so that unintended inputs such as palm touches can be undone. For an example of how to maintain history, see Implement a basic drawing app in the Enhance stylus support in an Android app codelab.
Key points
MotionEvent: Represents touch and movement events. Contains the information necessary to determine whether an event should be disregarded.OnTouchListener#onTouch(): ReceivesMotionEventobjects.MotionEvent#getActionMasked(): Returns the action associated with a motion event.ACTION_CANCEL:MotionEventconstant that indicates a gesture should be undone.ACTION_POINTER_UP:MotionEventconstant that indicates a pointer other than the first pointer has gone up (that is, has relinquished contact with the device screen).FLAG_CANCELED:MotionEventconstant that indicates that the pointer going up caused an unintentional touch event. Added toACTION_POINTER_UPandACTION_CANCELevents on Android 13 (API level 33) and higher.
Collections that contain this guide
This guide is part of these curated Quick Guide collections that cover broader Android development goals: