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.
Related
I have a problem with my app : I have a FrameLayout with a Fragment which contains a map from the Google Maps Android APi (v2), and a customized view which I use to display various buttons on top of the map.
I'd like some of these elements not to be shown while the map is being moved, for this I use the onTouchEvent() function of the View :
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
pressed = true;
invalidate();
break;
case MotionEvent.ACTION_UP:
pressed = false;
invalidate();
break;
}
return false;
}
The onDraw() function only displays the elements drawn over the map if pressed == false;
Now, my problem is in the return : if I put false, I say the event wasn't consumed, and the Android OS no longer notifies me when touch events are recorded, thus the MotionEvent.ACTION_UP isn't detected and the buttons stay hidden. If I put true, the touch events are no longer detected this time by the GoogleMap object, and I can't move the map around. Is there a way to keep detecting all future touch events, while not consuming the first event ?
Use onInterceptTouchEvent or dispatchTouchEvent.
You may read about the differences here: Android: Difference between onInterceptTouchEvent and dispatchTouchEvent?
So, here's my problem: in my game I made a countdown at the start of the game, during which the user can't press the screen, so I wait until the countdown is over to enable the OnSceneTouchListener. As soon as it's enabled, the user will be able to do some stuff moving the finger (not important what).
The problem is that if the user starts moving the finger while there's the countdown, as soon as it's over the onSceneTouchEvent method starts getting inputs, but it skips the ACTION_DOWN event since the user is already moving the finger.
To prevent this I could of course use a boolean inside the onSceneTouchEvent method, but this way it would always check that for every single input. It doesn't influence much the performance, but I'd rather find another way if it's possible.
So I was thinking, is there a way in the AndEngine to obtain the touch input event (with the information of the coordinate pressed, that's what I really need), so that I could "force" the ACTION_DOWN event by simple doing what I should do with it in the method that makes the countdown?
Thanks in advance!
Here is an example, how you can get touch coordinates.
public boolean onTouchEvent(MotionEvent event) {
int myEventAction = event.getAction();
float X = event.getX();
float Y = event.getY();
switch (myEventAction) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE: {
mySprite.setPosition(X, Y);
break;}
case MotionEvent.ACTION_UP:
break;
}
return true;
}
Source of this example
I'm currently developing an air-hockey simulation for android. For the multiplayer mode I'm tracking two touch events on the screen, which works well as long as the touch points don't get to close.
When the two fingers get to close, android only recognizes one touch event, in the middle of both points.
To make it even worse, android sometimes messes up the IDs after the collision.
I already thought about estimating the next touch points ans assigning IDs manually, does anybody know a better way, or knows about somebody who already fixed this problem programmatically?
NOTE: I'm testing on a Samsung Galaxy S 3
Not necessarily a logical fix to the issue, nevertheless a possible solution to the application:
If I'm not completely mistaken, air-hockey games shouldn't allow opponents to intrude on each others game field. If we assume a thick border cross the center of the screen (in portrait mode), then I wouldn't be allowed to do anything beyond that border, hence there is no point in tracking my finger after it reaches the border line.
Encapsulating your tracked touch events into valid physical locations as described might just help you in ignoring invalid points (given that the physical locations doesn't intersect, that is).
You might also have to keep track of direction of the touch vector: if the vector is stretching from the center of the screen towards "your end" it might be the opponents intruding finger or your own returning finger. In neither case should they affect the hockey puck (perhaps).
It may depend on the device you are using, but I'm using the code below in a Huawei X5 and It never mess up fingers, even if they touch each other or it I twist them over the screen.
private static PointF touchScreenStartPtArr[] = new PointF[10];
private static PointF touchScreenStopPtArr[] = new PointF[10];
private static PointF touchScreenCurrPtArr[] = new PointF[10];
OnTouchListener onTouchListenerMulti = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int fingerId = event.getPointerId(pointerIndex);
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
touchScreenStartPtArr[fingerId].x = event.getX(pointerIndex);
touchScreenStartPtArr[fingerId].y = event.getY(pointerIndex);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
touchScreenStopPtArr[fingerId].x = event.getX(pointerIndex);
touchScreenStopPtArr[fingerId].y = event.getX(pointerIndex);
break;
case MotionEvent.ACTION_MOVE:
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
touchScreenCurrPtArr[fingerId].x = event.getX(i);
touchScreenCurrPtArr[fingerId].y = event.getY(i);
}
break;
}
return true;
}
};
Note that I'm using fingerId and not pointerId to identify the correct finger, as pointer id may change when one finger is released.
Hope it works for you.
Here's the way I see it.
The touchscreen hardware gives you a resolution below which two touches are the same as one. This is something you cannot change.
Now the question is, what to do when two touches merge? (This is something that can be tested for programmatically one would think; e.g. if 2 touch pts -> 1 touch pt. AND prev touch pt 1 is close enough to prev touch pt 2...). In your case, I would move both pucks along the merged touch gesture until they separate, then return individual control.
Of course, I see several problems with this, like which touch controls which puck after the split? Maybe one person lifted their finger during the merge.
You could have both players lose control of their puck if a merge occurs. This could simulate the shock to the wrist as your hand bashes into your opponent's :)
I also like #dbm idea.
Hope this helps. Probably didn't :)
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).
Currently I have a zoom implemented for my drawing application which works quite well. Just some lines so you know what I'm talking about:
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent rawEvent) {
WrapMotionEvent event = WrapMotionEvent.wrap(rawEvent);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
drawSomethingHere();
case MotionEvent.ACTION_POINTER_DOWN:
startZoomingModeHere();
...
So what I want is: draw with one finger, zoom with both fingers.
Problem is: there is always a ACTION_DOWN event triggered BEFORE the second finger hits the surface. So everytime I want to zoom, my app draws a point before the zoom mode is started.
Does someone has an idea how to solve this?
I think you should wait some milliseconds before starting draw, because it's impossible to put exactly two fingers at same millisecond.
You could have a boolean var to wait.
boolean boolean_pointer_down = false;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// Start a thread to call drawSomethingHere in 300 - 700 milliseconds
// if action_pointer_down haven’t been called.
new ThreadDraw().start();
case MotionEvent.ACTION_POINTER_DOWN:
boolean_pointer_down=true;
startZoomingModeHere();
....
//Method run in the thread
public void run(){
wait(300); //if the user didn't put more fingers in 300 ms he's not going to zoom
if (!boolean_pointer_down){
drawSomethingHere();
boolean_pointer_down = false;
}
}
Solved as follows:
Draw on ACTION_UP and ACTION_MOVE instead of ACTION_DOWN
On ACTION_MOVE don't draw immediately, put the points in a buffer instead (this will make sure that you don't interpret accidental single touch events before the multitouch event happens)
as soon as the buffer has 3 points, start the drawing mode
as soon as an ACTION_POINTER_DOWN event occurs (multitouch happened), clear the buffer and start zooming mode
This is the best I could do. The result is pretty convincing...