speed or acceleration of motion event android - android

Is it possible to get the speed or velocity or acceleration of touch event in android with the existing api? I have gone through MotionEvent class and none of the fields in that class seem to retrieve information that i need. Any help would be greatly appreciated

MotionEvent does not help you in this case. You can use VelocityTracker class. It gets MotionEvent instances and calculates velocity of recent touch events.
You can take a look at its documentation here:
http://developer.android.com/reference/android/view/VelocityTracker.html
First you have to get an instance by obtain() method:
VelocityTracker velocity = VelocityTracker.obtain();
then you can add ACTION_MOVE events to its queue:
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
velocity.addMovement(event);
}
then you can compute velocity and extract x_velocity and y_velocity
velocity.computeCurrentVelocity(1000);
float x_velocity = velocity.getXVelocity();
float y_velocity = velocity.getYVelocity();
I hope it works for you.

You need to calculate velocity manually between each two events using System.nanoTime. Same way for acceleration (but using velocity instead of coordinates this time).

Related

Is there a offset between onTouchEvent and onTouchListener?

I have developed a game that shoots when player touches the screen by using onTouchListener for my custom SurfaceView and Thread.
But now I want to change the approach and instead of onTouchListener I added onTouchEvent to the SurfaceView o my Activity.
The problem is that I get some kind of offset when I click on the emulator.
Everything is working great, except that offset keeps appearing and I don't understand why.
Also let me mention that my app is running in landscape mode, maybe this is relevant.
I suspect that it isn't working properly because onTouchListener was added to the view and depended on it, but onTouchEvent doesn't depend on the view.
Also my view doesn't have any padding or margin properties, it is full-screen view (fill_parent).
Does anyone have any ideas on this?
I have done my application, and everything works correctly now, but i still do not know what the problem was.
After lots of debugging of my application the onTouchEvent returned random Y values that were always higher than the ones that the onTouchListener returned. And i am not sure why this is hapening since my view that recognizes the onTouchListener is a full-screen view.
So i figured out a way to get passed this by doing some math.
The first function that the android calls is the onTouch method which gives the correct values but just for one touch. I needed it to give right values even on the MotionEvent.ACTION_MOVE so i noticed that MotionEvent.ACTION_MOVE is actually doing correctly depending on the first touch recognized by the onTouchEvent.
So i just got the coordinate Y from the onTouch and the different coordinate with the offset from onTouchEvent calculated the difference and in every onTouchEvent from there, until the user lifts up their finger, i just subtract that difference and that gives me the correct value.
If anyone else has this problem, and doesn't know how to fix it, here is my code, maybe it will be helpful.
#Override
public boolean onTouchEvent(MotionEvent arg1) {
/*you can only touch when the thread is running*/
if(game.state() != STATE_PAUSE){
if(arg1.getAction() == MotionEvent.ACTION_DOWN){
coordinateX = arg1.getX();
coordinateY = arg1.getY();
differenceY = Math.abs(coordinateY - touchedY);
coordinateY = coordinateY - differenceY;
shootingIsOkay = true;
game.setDrawCircle(coordinateX,coordinateY);
}
if(arg1.getAction() == MotionEvent.ACTION_MOVE){
coordinateX = arg1.getX();
coordinateY = arg1.getY();
coordinateY = coordinateY - differenceY;
shootingIsOkay = true;
game.setDrawCircle(coordinateX,coordinateY);
}
if(arg1.getAction() == MotionEvent.ACTION_UP){
shootingIsOkay = false;
}
}
return false;
}
And the onTouch method that is called from the onTouchListener that depends on the view is just simple, here:
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
touchedY = arg1.getY();
return false;
}
If anyone knows how to fix this problem, please post your answer, i am very curious why this is happening

GestureDetector Multi-touch

I'm working with touch gestures in Android using the OnGestureListener interface and GestureDetector.
I made an app to test if detecting two fingers works, in onFlp(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY), I print the id of the different MotionEvents but these ids are the same (apparently only detects one finger).
Does GestureDetector support multi-touch events?
The Issue
Using OnGestureListener to detect multitouch gestures does not seem to be implemented by default.
The first thing you may have tried is reading event.pointerCount to get the count of fingers on the screen. However, this will be equal to 1. This is because you will (quite likely) never be able touch the screen with both fingers in exactly the same millisecond.
Fixing it
You have to buffer pointerCount (the amount of fingers on screen). First add those variables somewhere in the context that you intend to track gestures in:
// track how many fingers are used
var bufferedPointerCount = 1
var bufferTolerance = 500 // in ms
var pointerBufferTimer = Timer()
Then, in the onTouchEvent(event: MotionEvent) function, you add this:
// Buffer / Debounce the pointer count
if (event.pointerCount > bufferedPointerCount) {
bufferedPointerCount = event.pointerCount
pointerBufferTimer = fixedRateTimer("pointerBufferTimer", true, bufferTolerance, 1000) {
bufferedPointerCount = 1
this.cancel() // a non-recurring timer
}
}
Essentially this tracks the maximum amount of fingers on the display and keeps it valid for bufferTolerance milliseconds (here: 500).
I currently am implementing it in a custom Android Launcher I created (finnmglas/Launcher | see related issue)

Fling implementation on android canvas

I have the usual gesture detector for detecting fling , It is an instance attribute of a SurfaceView
GestureDetector flingDetector = new GestureDetector(getContext(),new SimpleOnGestureListener() {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// Fling implementation
return true;
}
});
I am drawing a lot of complex stuff on a canvas and I have a translate(dx,dy) method that I use with onScroll.
So my question is how do I implement the fling using the translate method ?
There seem to be a lot of questions on detecting fling , my question is on implementing it .
I am not sure this will answer your question, I'll give it a try.
Check http://developer.android.com/reference/android/view/MotionEvent.html for MotionEvent.
You can use the two events received as e1 and e2 on the onFling method, and calculate coordinate differences with e1.getX(), e2.getX(), e1.getY(), e2.getY().... With this you would have the dx and dy to use with translate(dx,dy).
Since the fling seems more of a dynamic gesture, you could decide that fling means an ampler movement, and apply an amplification factor to dx and dy, so that when the user scrolls, they get a precise movement, but on fling, the actual movement gets amplified.
If this factor depends on velocity, you have a custom response for every user input.
(A different thing would be animating the result, which I guess would depend on other things).
An example I might try if it were me:
User scrolls softly: Movement is dx,dy. Translate(dx,dy).
User flings:
Real motion: dx=(e2.getX()-e1.getX(). dy = (e2.getY()-e1.getY().
Fling factor: (Custom implementation).
Modified motion: dxModified = dx*velocityX*F. dyModified = dy*velocityY*F.
Finally: translate (dxModified,dyModified)
Hope this helps to some extent.
Edit: I did not realize this question was from 2012, hopefully this will help someone some time. It would be nice to know about the final implementation anyway!.

Adjust touch input sample rate on Android

On Android, is there a way of adjusting the touch input sample rate?
You can't stop the system generating these events however you can selectively ignore some of the ACTION_MOVE events as you will see up to 60 per second each reporting the same co-ordinates.
You may wish to only process these ACTION_MOVE events after a set time since the last event, or skip to every 5th or 10th event etc. You'll have to experiment and see what works best for you.
Just make sure you don't skip ACTION_UP or your application may get into a confused state with the touches.
I'm supposing you're trying to adjust the rate as you dealing within onTouch function.
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
downTime = event.getDownTime();
// Do something you want to.
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
eventTime = event.getEventTime();
if(eventTime - downTime > 25){
// Do something you want to.
}
break;
}
}
You should declare long variable downTime and eventTime in your class.
Also the unit of them is ms.
Hope that will help you out.
2011/7/20
Maybe you can try:
Tread.sleep(time);
See if it helps.

android.view.GestureDetector.OnGestureListener onFling() vs onScroll()

What is the difference of events of onFling() and onScroll() of android.view.GestureDetector.OnGestureListener?
link text
onScroll() happens after the user puts his finger down on the screen and slides his finger across the screen without lifting it. onFling() happens if the user scrolls and then lifts his finger. A fling is triggered only if the motion was fast enough.
Actually onFling has nothing to do with the speed at which the movement ocurred. It's the user, via the velocityX and velocityY parameters that determine if the speed (or distance, via the MotionEvent parameters) was good enough for their purposes.
The onScroll is constantly called when the user is moving his finger, where as the onFling is called only after the user lifts his finger.
You can see the code of framework/base/core/java/android/view/GestureDetector.java, at the onTouchEvent() method. onFling() is called in case of MotionEvent.ACTION_UP and velocityY > mMinimumFlingVelocity or velocityX > mMinimumFlingVelocity. onScroll() is called in case of MotionEvent.ACTION_MOVE.
You can differentiate between the two after the onFling() happens. First, in onDown() store the current coordinates of the image as class variables. The onScroll() will work as expected but if the onFling() determines that this is a fling event, just restore the original coordinates that were stored in onDown(). I found this works very well.
#Override
public boolean onDown(MotionEvent e) {
// remember current coordinates in case this turns out to be a fling
mdX = imageView.dX;
mdY = imageView.dY;
return false;
}

Categories

Resources