Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android GestureDetector with SimpleOnGestureListener within SurfaceView

public class GameActivity extends Activity {
    private static final String TAG = "GameActivity";

   . . .

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "+ onTouchEvent(event:" + event + ")");
        Log.d(TAG, "- onTouchEvent()");
        return super.onTouchEvent(event);
    }

    . . .
}


public class GameView extends SurfaceView implements SurfaceHolder.Callback {
    private static final String TAG = "GameView";

    . . .

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "+ onTouchEvent(event:" + event + ")");
        gestureDetector.onTouchEvent(event);
        Log.d(TAG, "- onTouchEvent()");
        return super.onTouchEvent(event);
    }

    private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
        private static final String TAG = "GestureListener";

        @Override
        public boolean onSingleTapConfirmed(MotionEvent event) {
            Log.d(TAG, "+ onSingleTapConfirmed(event:" + event + ")");
            singleTapDetected = true;
            Log.d(TAG, "- onSingleTapConfirmed()");
            return true;
        }

        @Override
        public boolean onDoubleTap(MotionEvent event) {
            Log.d(TAG, "+ onDoubleTap(event:" + event + ")");
            doubleTapDetected = true;
            Log.d(TAG, "- onDoubleTap()");
            return true;
        }
    };

    private GestureDetector gestureDetector = new GestureDetector(getContext(), gestureListener);

    . . .
}

I ran it on AVD an made a single click on the SurfaceView (GameView).
According to LogCat logs:

03-11 14:19:51.171: D/GameView(4839): + onTouchEvent(event:MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=1071.0, y[0]=437.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=27223172, downTime=27223172, deviceId=0, source=0x1002 })
03-11 14:19:51.171: D/GameView(4839): - onTouchEvent()
03-11 14:19:51.171: D/GameActivity(4839): + onTouchEvent(event:MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=1071.0, y[0]=437.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=27223172, downTime=27223172, deviceId=0, source=0x1002 })
03-11 14:19:51.171: D/GameActivity(4839): - onTouchEvent()
03-11 14:19:51.299: D/GameActivity(4839): + onTouchEvent(event:MotionEvent { action=ACTION_UP, id[0]=0, x[0]=1071.0, y[0]=437.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=27223303, downTime=27223172, deviceId=0, source=0x1002 })
03-11 14:19:51.299: D/GameActivity(4839): - onTouchEvent()

There are several questions:

  1. Why the SimpleOnGestureListener was not called? (Even though onTouchEvent() was called and presummably the line gestureDetector.onTouchEvent(event); was executed)

  2. Why the GameActivity's onTouchEvent() gets ACTION_DOWN and ACTION_UP, but the GameView's onTouchEvent() only gets ACTION_DOWN?

Some things I have tried

  • I implemented the GestureDetector on the GameActivity class with the same code as shown above and it worked as expected, calling onSingleTapConfirmed()

  • In GameView, instead of a private member SimpleOnGestureListener, created a private class GestureListener extends SimpleOnGestureListener and used it to construct the GestureDetector. I see the same behavior as described, no call to the listener.

like image 475
ilomambo Avatar asked Feb 17 '23 05:02

ilomambo


1 Answers

I debugged the code into the android source code, GestureDetector class. And this explains why SimpleOnGestureListener was not called:

  • The ACTION_DOWN is received and generates an internal TAP message to the GestureDetector message Handler.
  • The Handler calls the listener onSingleTapConfirmed() only if the event is not still down (!mStillDown)
  • The event is still down, because the ACTION_UP event was never received.

So you see, the two questions are related, when I find out why ACTION_UP is not issued I will solve the problem!

Edit

This completes the answer, now it is working.

  • The call to super.onTouchEvent() in GameView returns false, because the super class of SurfaceView is View, and it returns false. That's why ACTION_UP is never called
  • The call to super.onTouchEvent() in GameActivity returns true, that's why ACTION_UP is issued on GameActivity.

Note: If I set GameView.setclickable(true) then super.onTouchEvent() returns true. It is also an acceptable solution

Now my GameView code is:

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG, "+ onTouchEvent(event:" + event + ")");
    gestureDetector.onTouchEvent(event);
    Log.d(TAG, "- onTouchEvent()");
    return true;
}

The current LogCat logs are:

03-11 16:32:06.629: D/GameView(5316): + onTouchEvent(event:MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=977.0, y[0]=414.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=35158623, downTime=35158623, deviceId=0, source=0x1002 })
03-11 16:32:06.629: D/GameView(5316): - onTouchEvent()
03-11 16:32:06.641: D/GameView(5316): + onTouchEvent(event:MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=978.0, y[0]=414.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=35158623, downTime=35158623, deviceId=0, source=0x1002 })
03-11 16:32:06.641: D/GameView(5316): - onTouchEvent()
03-11 16:32:06.772: D/GameView(5316): + onTouchEvent(event:MotionEvent { action=ACTION_UP, id[0]=0, x[0]=978.0, y[0]=414.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=35158772, downTime=35158623, deviceId=0, source=0x1002 })
03-11 16:32:06.772: D/GameView(5316): - onTouchEvent()
03-11 16:32:06.931: D/GestureListener(5316): + onSingleTapConfirmed(event:MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=977.0, y[0]=414.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=35158623, downTime=35158623, deviceId=0, source=0x1002 })
03-11 16:32:06.931: D/GestureListener(5316): - onSingleTapConfirmed()
like image 127
ilomambo Avatar answered May 07 '23 15:05

ilomambo