Detecting touch coordinates, while letting the click go below (Android Studio)

29 Views Asked by At

I need to get the coordinates of any touch the user performs, while not eating the click, so that views below can receive the click. Basically, if the user opens a folder, or opens Google, I get the coordinates, and the folder, or Google, get opened. I've thought of using an overlay with the AccessibilityService and a WindowManager, however the view seems to eat up all the clicks, not letting any be passed below! The click coordinates should be received from the whole screen, meaning on top of other apps as well, using the traditional xml views. Here is the code that I initially used:

// Inside the AccessibilityService class
override fun onServiceConnected() {
    val wm = getSystemService(WINDOW_SERVICE) as WindowManager

    // Create an overlay
    val mLayout = FrameLayout(this)
    val lp = WindowManager.LayoutParams()
    lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
    lp.format = PixelFormat.TRANSLUCENT
    lp.flags = lp.flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    lp.width = WindowManager.LayoutParams.MATCH_PARENT
    lp.height = WindowManager.LayoutParams.MATCH_PARENT
    lp.gravity = Gravity.TOP
    LayoutInflater.from(this).inflate(R.layout.my_layout, mLayout)
    wm.addView(mLayout, lp)

    // Set a touch listener on the overlay
    mLayout.setOnTouchListener(object : View.OnTouchListener {
        override fun onTouch(v: View, event: MotionEvent): Boolean {
            when (event.action) {
                MotionEvent.ACTION_UP -> {
                    Log.v("TAG", "Coordinates: ${lp.x} - ${lp.y}")
                    return true
                }
            }
            return false
        }
    })
}

I do have one solution, which is setting up buttons on expected positions, and when the user clicks one, the buttons visibility gets set to View.GONE, and I use the dispatchGesture function to perform a click on the position of the button (if it was not made GONE, it would've eaten the click). Here is the main part of my code for that as well:

val handler = Handler(Looper.getMainLooper())
layout.setOnClickListener {
    // Make the layout gone, so that the click goes through
    layout.visibility = View.GONE
    val location = IntArray(2)
    layout.getLocationOnScreen(location)
    val newX = location[0] + layout.width / 2f
    val newY = location[1] + layout.height / 2f
    val swipePath = Path()
    swipePath.moveTo(newX, newY)
    val gestureBuilder = GestureDescription.Builder()
    gestureBuilder.addStroke(StrokeDescription(swipePath, 0, 1))
    // Click on the position of the button
    dispatchGesture(gestureBuilder.build(), object : GestureResultCallback() {
        override fun onCompleted(gestureDescription: GestureDescription?) {
            super.onCompleted(gestureDescription)
            // Back to visible once done clicking
            layout.visibility = View.VISIBLE
        }
    }, handler)
}

I could also use an overlay again, and do the same, while getting the coordinates of the click instead of using buttons, then making it GONE and dispatching a gesture, however either way there is quite a troubling delay between the press (the users click) and the opening action (so the folder, Google, etc.)

0

There are 0 best solutions below