I use Activity.onUserInteraction() to detect when a user touches any area of the screen when the app is running.
I've noticed that it also get's called when switching between activities (without user touching the screen) therefore leading to false counts of screen touches.
Why is that?
What are other alternatives for getting screen touches?
Why is that?
I'm not 100% sure, but the documentation for this method gives a potential answer:
This callback and onUserLeaveHint() are intended to help activities manage status bar notifications intelligently; specifically, for helping activities determine the proper time to cancel a notification.
Through this lens, it makes sense that you would get this callback when switching activities, regardless of whether a human interaction caused the switch.
What are other alternatives for getting screen touches?
You could override dispatchTouchEvent(MotionEvent) in a "base" Activity class to be notified of every touch event. This would mean that you'd be called for every event in a single gesture (e.g., you'd be called many times for a single swipe gesture), but you could perhaps decide to react only to ACTION_DOWN events or similar.
Related
I'm new to Java but handling it quite well because of my years of programming with python (basic concepts carry from language to language).
I have a practice project set up and the only propose of this project is for me to learn how to do things the java/android studio way, logic wise.
So logically, the last python based api I used, there was a way to issue your own ID to touches and keep track of those touches; therefore you knew if a touch still existed or not.
That's where I am right now. I know how to get the touch ID and then get the Index that holds the touch data. Basically I'm using a For Loop on the motion event to process all touches to the screen.
Here's the thing....
Lets say I have 10 touches to process and what I do in a loop is basically collect the info of the touches and store them in a hashtable, so I can then later process all the touches in the hashtable.
So as I pull a touch data from the hashtable to process, I want to first check to see if the touch still exits. I'm guessing once a touch enters the "UP" state, it goes out of scope after that because a touch is over after release.
Sure I can just check the "Action" to see if it's equal to "UP" but if the touch doesn't exits anymore, that would raise and exception...right?
What I thought about doing was, calling "getPointerCount" again, looping through and getting the IDs again and see if the ID of a touch in my hashtable still exits in the MotionEvent and if the ID exists and the "Action" is still equal to "DOWN", then process the touch. Otherwise, if the ID does not exists or the "ACTION" is equal to "UP", do a release button event if needed or just delete the touch from my hashtable because it doesn't exits anymore.
I can't help but get the feeling of redundancy though when considering that approach.
Is there a way or method I don't know about that allows you to check if a touch still exits before you process actions relating to it?
I was thinking just now.... Well, kind of guessing that, if you have five touches that hit the screen and one of the touches triggers the opening of a menu and that button had higher priority over the other four touches, you could simply ignore the other for touches for that frame and open the menu and in the next frame of the app, if the other four touches are still down, you can deal with them then accoring to their priority..... But then again, the touch could still exists in the next frame but the "Action" may be "UP" or "MOVE" instead of down, thus allowing one to write code for a release or move event. With this thought, storing touch data in a hashtable is really not needed then, granted a touch this is on action "UP" will go out of scope in the very next frame (I'm guessing).
......hum......
Maybe I'm just over thinking it.
Forgive any "typos", eyes are that super any more.
The code I wrote was correct but I wasn't getting the results because I was using MotionEvent.getAction().
For anyone new to Android Studio and its APIs, do not use MotionEvent.getAction(). Instead, use MotionEvent.getActionMasked()...otherwise, multi-touch will not work correctly.
For me, only the 1st touch was registering when I was doing a double button press test. I thought my code was flawd but all was working correctly when I used MotionEvent.getActionMasked().
Turns out, MotionEvent.getAction() just doesn't return an Action...other data is attached to it, which throws off your code.
MotionEvent.getActionMasked() returns the Action only.
I am facing an issue if user touches multiple button within a small time interval(less than 1 second). I want only one of them to be executed. Similar issue with touch and swipe as well.
I have tried below solutions:
Use a boolean flag and set inside onClickListener. If this flag is then directly return from onClickListener. This approach does not work for me as it is not very deterministic to decide correct place to unset the flag.
Check time difference between two consecutive onClicListener and ignore 2nd if it is less than some threshold value. Issue with this approach that it is not very deterministic and threshold may vary for devices. Also if I keep it very high and device will appear to be very slow.
What I want is 2nd touch to not even register if first touch onClickListener is not completed. Are there other ways to control the touch events in Android?
What you're looking for is a debouncer / debounced click listener. You can find implementation details by searching using these terms, with some examples here - https://medium.com/swlh/android-click-debounce-80b3f2e638f3 - and here - Avoid button multiple rapid clicks.
I have a floating app which works perfectly.
I am using OnTouchListener to catch events since I need to use the GestureDetector for swipes etc.
My only problem is that sometimes I wish to ignore certain events on the view.
In this case the view is invisible but not "gone" because I need it to accept certain gestures but not others.
I can't seem to be able to do that.
Returning false from "onTouch" simply doesn't work.
I checked that by experiment by disabling the GestureDetector and simply always returning false just to see what would happen. Result was nothing going through.
Is it even possible to pass a click through to a covered app?
Due to security reasons it's not possible to record and pass a click below (essentially allows building a keylogger).
Best you can do is have your floating window small enough to start the touch but not cover too much of the screen below.
I am working on a background service that runs to give sound feedback device-wide whenever the user is touching the screen. I tried to create an overlay with a custom view to listen to touches and pass them down to the views below in a similar direction to what was attempted in this question but my overlay seemed to be either consuming all the touch events or if I returned false only the down touch was detected.
I was wondering if there was perhaps an accessibility route I could take? Basically I need a way to get the information of any current touches on the screen (preferably multitouch) I don't need to alter the touch event or anything, just need the information.
I wish to sometimes (when a flag is on) update a few UI components in an Android activity every drawn frame (i.e., not while app is not visible, and not more than once per frame). How do I do this?
The question specifically states "every drawn frame", which suggests that overriding onDraw() in whatever it is that's being drawn will solve your problem exactly.
If that's not quite what you're going for, you should take a look at Choreographer, which invokes a callback once per display refresh. You must renew the callback every time it is invoked. To stop the callbacks when the Activity is in the background, establish the callback in onResume(), and set a flag in onPause(); if the callback sees the flag set, it doesn't renew itself.
The documentation for Choreographer notes higher-level API features that do common things. If one of those fits your needs, prefer that over the use of the lower-level API.