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.)