msto
msto

Reputation: 63

Avoid coalescing of ACTION_MOVE MotionEvents in Android

I was trying to accurately read ACTION_MOVE deltas from a sequence of MotionEvents in Android.

My tests with swiping a finger over the screen however suggest that after the initial ACTION_DOWN, several MotionEvents are not delivered to the listener. Only after a sufficiently large move is made, a ACTION_MOVE event is delivered with a relatively large delta. After this first ACTION_MOVE event, all deltas are very small again.

Alternatively, one can also touch the screen (ACTION_DOWN) and slightly move around and no ACTION_MOVE event is delivered at all.

I understand that for many uses, having a certain move (in)sensitivity is beneficial. However, is there a way to avoid coalescing of ACTION_MOVE events such that every small initial move is delivered? Is there a threshold that can be set on the minimum distance between the ACTION_DOWN position and the first ACTION_MOVE position?

Here is some sample code:

private float lastX;
private float lastY;

public boolean onTouch(View v, MotionEvent ev) {

    final float y = ev.getX();
    final float x = ev.getY();

    final int hs = ev.getHistorySize();

    final int ac = ev.getAction();
    switch(ac)
    {
        case MotionEvent.ACTION_DOWN:
        {
            this.lastX = x;
            this.lastY = y;
            Log.i("TEST", "Down at " + x + "/" + y + " (History size="+hs+")");
            return true;
        }
        case MotionEvent.ACTION_MOVE:
        {
            Log.i("TEST", "Move at " + x + "/" + y + ": Delta="+(lastX-x)+"/"+(lastY-y) + " (History size="+hs+")");
            this.lastX = x;
            this.lastY = y;
            return true;
        }
        case MotionEvent.ACTION_UP:
        {
            Log.i("TEST", "Up at " + x + "/" + y + " (History size="+hs+")");
            return true;
        }
    } 
}

And the corresponding output:

Down at 376.0/259.0 (History size=0)
Move at 392.0/268.0: Delta=-16.0/-9.0 (History size=0)
Move at 394.0/268.0: Delta=-2.0/0.0 (History size=0)
Move at 395.0/269.0: Delta=-1.0/-1.0 (History size=0)
Move at 394.0/268.0: Delta=1.0/1.0 (History size=0)
Move at 396.0/269.0: Delta=-2.0/-1.0 (History size=0)
Move at 399.0/271.0: Delta=-3.0/-2.0 (History size=1)
Move at 401.0/272.0: Delta=-2.0/-1.0 (History size=0)
Move at 403.0/273.0: Delta=-2.0/-1.0 (History size=0)
Move at 404.0/273.0: Delta=-1.0/0.0 (History size=0)
Move at 405.0/274.0: Delta=-1.0/-1.0 (History size=0)
Move at 406.0/275.0: Delta=-1.0/-1.0 (History size=0)
Up at 406.0/275.0 (History size=0)

In other words, I want to avoid the large delta at the second line (-16/-9) but receive deltas in the order of 1 or 2 ...

I made tests on the Samsung Galaxy S2 and Note.

Any help or suggestion is highly appreciated!

Upvotes: 2

Views: 3985

Answers (2)

Luis
Luis

Reputation: 12048

I'm using MotionEvent in some apps and necer faced this issue.

If you using a SDK version > 4 then MotionEvent supports multitouch. I'm testing this on my apps and use a modiffied listener to get the touch events. Code bellow:

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; 
    } 
}; 

--EDIT--

The result of running your code in device Huawei X5:

Down at 387.29388/247.27272 (History size=0)
Move at 387.29388/247.27272: Delta=0.0/0.0 (History size=0)
Move at 387.29388/247.27272: Delta=0.0/0.0 (History size=0)
Move at 387.29388/245.39589: Delta=0.0/1.876831 (History size=0)
Move at 387.29388/244.92668: Delta=0.0/0.46920776 (History size=0)
Move at 387.29388/244.45747: Delta=0.0/0.46920776 (History size=0)
Move at 387.29388/243.98827: Delta=0.0/0.46920776 (History size=0)
Move at 387.29388/243.51906: Delta=0.0/0.46920776 (History size=0)
Move at 389.01614/243.51906: Delta=-1.7222595/0.0 (History size=0)
Move at 389.8773/243.51906: Delta=-0.861145/0.0 (History size=0)
Move at 389.8773/243.04985: Delta=0.0/0.46920776 (History size=0)
Move at 390.73843/243.04985: Delta=-0.861145/0.0 (History size=0)
Move at 390.73843/242.58064: Delta=0.0/0.46920776 (History size=0)
Move at 391.59958/242.58064: Delta=-0.861145/0.0 (History size=0)
Move at 391.59958/242.11143: Delta=0.0/0.46920776 (History size=0)
Move at 392.46072/242.11143: Delta=-0.861145/0.0 (History size=0)
Move at 392.46072/241.64223: Delta=0.0/0.46920776 (History size=0)
Move at 393.32187/241.64223: Delta=-0.861145/0.0 (History size=0)
Move at 394.183/241.64223: Delta=-0.861145/0.0 (History size=0)
Move at 394.183/241.17302: Delta=0.0/0.46920776 (History size=0)
Move at 395.04413/241.17302: Delta=-0.8611145/0.0 (History size=0)
Move at 395.04413/242.11143: Delta=0.0/-0.9384155 (History size=0)
Move at 395.04413/242.58064: Delta=0.0/-0.46920776 (History size=0)
Up at 395.04413/242.58064 (History size=0)

It looks like you may have another listener stealing events from this one.

I would suggest that you check your code (you need to a add a "return false" in the end) in a cleaning project, just to be confirm it.

good luck.

Upvotes: 1

Timmmm
Timmmm

Reputation: 96546

I hate to break it to you, but this is entirely Samsung's fault and will only happen on a Galaxy S2. Basically they added a software touch threshold in the input driver for no real reason.

I once tried to convince them to remove the threshold, but they didn't seem to understand the problem and told me that is was deliberate! Despite this, they have fixed it in the Galaxy S3.

Fortunately it isn't a hardware limitation, so you can get around it if you have a rooted phone, or install a custom ROM.

Upvotes: 4

Related Questions