2

I'm currently working on an Android application which allows the user to play a violin as they move their finger left and right across the screen. I wish to make the music stop playing when they stop moving their finger and the violin's bow stops moving.

I'm using a typical onTouchEvent to capture the movement gesture, and now I'm wondering the best way to detect the user is user is still touching the screen, but is not moving their finger.

This is my code at the moment with an extremely spaghetti function to detect the amount of movement, which runs into the following two problems:

1: As the user moves from left to right, it will register it as no movement for a split second and stop the sound.

2: It's impossible to hold your finger perfectly still, I need to allow for small amount of movements.

Can anyone suggest the correct way of detecting the lack of movement than below?

public boolean onTouchEvent(MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_DOWN) {

        audio.start();
        bowImage.setY(430);

    } else if (event.getAction() == MotionEvent.ACTION_MOVE) {

        float posX = event.getX();

        if ( detectValidMovement(posX) ) {
            bowImage.setX(posX);
            audio.start();
        } else {
            audio.pause();
        }


    } else if (event.getAction() == MotionEvent.ACTION_UP) {

        audio.pause();

    }
    return true;
}



private boolean detectValidMovement(float posX) {

    int newX = Math.round(posX);

    if (oldX > 0) {

        int distanceMoved = newX - oldX;

        if (oldX != newX) {
            oldX = newX;
            return true;
        } else {
            oldX = newX;
            return false;
        }
    } else {
        oldX = newX;
    }
    return false;   
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Joseph Woodward
  • 9,191
  • 5
  • 44
  • 63

1 Answers1

1

There are other factors at play. There seems to be a default touch "slop" of about 10px. This means that onTouchEvent won't fire for anything under that threshold. So, you need to find out if they're stopped without relying on onTouchEvent at all. One way is to set a lastTouched each time it runs to set the time, and run a timer loop to check it against the current time.

Now, if you want a threshold higher than 10px, you'll also have to arrange that yourself. Something like:

final int threshold = 25;

private boolean detectValidMovement(float posX) {

    int newX = Math.round(posX.getX());
    double distance = Math.abs(newX - oldX);
    oldX = newX;
    if(distance < threshold)
        return false;

    return true;
}

Notice the use of Math.abs() to check both directions, and that this only checks X movement. I assumed that's all you're concerned about from your code sample.

That's really all you need for that part. Check oldX > 0 doesn't make much sense, because it doesn't matter to movement. Checking oldX != newX is covered by distance < threshold, so you can get rid of that.

The trickier part is going to be setting up the timer in case onTouchEvent doesn't fire.

Community
  • 1
  • 1
Geobits
  • 22,218
  • 6
  • 59
  • 103
  • Can you shed some light on how the "trickier part" can be done? Let's say we set up the timer to periodically run a routine. How can we get X and Y inside the routine? When using onTouch, we can call event.getX() and event.getY(), but what can we do when we periodically call our own routine in absence of any events? Thanks! – FCA Jun 06 '13 at 21:21