2

I have an app which detects swipe on edge of the screen using an overlay view. Now I wanted to add an action which will be performed when the overlayed view is touched and held without moving. However, I observed some weird behaviours, which I suspect, after hours of trying and searching, is caused by the accidental palm touch rejection feature of Android. My observations:

  • If I touch and hold for some duration and then release without moving, no event is detected. (this is the problem)
  • If I quickly touch and release, both action down and up events are generated consecutively.
  • The above behave the same way with both MotionEvent and onClickListener.
  • If I touch and hold as long as I want, and then move without releasing, both down and move events are generated as soon as move starts.
  • If I remove FLAG_NOT_FOCUSABLE and FLAG_NOT_TOUCH_MODAL flags and write 0 there, whole screen becomes touchable and detects the touches correctly, except the left/right edges.
  • If I place the overlay away from the edge towards middle of the screen, everything works correctly.
  • On android emulator, everything works well with mouse clicks on default overlay position.
  • So, I attached a mouse to my physical phone with OTG, it also works correctly with mouse clicks.
  • In the main settings activity of the app, same behaviour is observed on preference buttons. No button animation when pressing and holding on edge of the screen, but animation and click works if I quickly touch and release.

I tried all flags of WindowManager.LayoutParams, tried to capture dispatch events of the view, none worked.

Is the problem palm rejection feature? Is there a way to bypass this and detect touch and hold (preferably with custom hold duration) on edges of the screen on overlay?

Note: Tried on Pixel 2 XL, Android 11.

val overlayedButton = View(this)

val overlayedWidth = 30
val overlayedHeight = resources.displayMetrics.heightPixels / 2

val LAYOUT_FLAG: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
    @Suppress("DEPRECATION")
    WindowManager.LayoutParams.TYPE_PHONE
}

val params = WindowManager.LayoutParams(
    overlayedWidth,
    overlayedHeight,
    LAYOUT_FLAG,
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
    PixelFormat.TRANSLUCENT
)

params.gravity = Gravity.RIGHT

params.x = 0
params.y = 0

if (overlayedButton!!.parent == null)
{
    wm!!.addView(overlayedButton, params)
}
else
{
    wm!!.updateViewLayout(overlayedButton, params)
}

overlayedButton!!.setOnTouchListener(this)
override fun onTouch(v: View, event: MotionEvent): Boolean {
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            //...
    }
        MotionEvent.ACTION_MOVE -> {
            //...
    }
        MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
            //...
    }
    //...
}
    
Hasmet D
  • 21
  • 1
  • 4
  • have you tried with different device? but at first: what type of navigation are you using on this problematic Pixel? if gesture one then there may be some conflict with "back" gesture, have you tried with old-fashioned 3-buttons-navigation set up in system Settings? – snachmsm Mar 23 '22 at 10:54
  • I didn't try on any other device, but I want this to work on all devices. I'm using 3-button navigation. – Hasmet D Mar 23 '22 at 11:48
  • I'm researching the same issue. Having dealt with a similar problem on iOS, I'm leaning more toward the interpretation that the os is intercepting those touches near the edge for system gestures (back swipe) and not sending them over to the app layer. The case where you quickly tap and release would be explained by the OS realizing it is not a gesture and sending both events. – ADB May 05 '22 at 15:10

1 Answers1

0

Maybe take a look at setSystemGestureExclusionRects. Also this article explains what is going on with the OS intercepting touches for high-level gestures.

ADB
  • 2,319
  • 1
  • 24
  • 35
  • Thanks, I tried this today but it didn't work or I couldn't make it work. In my case gesture and tap works, so maybe this is indeed because of palm rejection? Otherwise, I think gesture would be blocked as well. – Hasmet D May 06 '22 at 18:40