Q:

"Spamming touches" on Jelly Bean causes application to crash, works on Gingerbread

I'm writing a platform game and i have a problem with multitouch on devices with Jelly Bean. I have 3 buttons on screen - left arrow, right arrow nad jump button. On my phone with Gingerbread i can rapidly press the buttons and application wont crash but on my friend's phone with Jelly Bean it crashes as soon as he starts spamming buttons (i mean more than one at a time so i guess its a problem with multitouch). Here's my code which handles touches:
public boolean onTouchEvent(MotionEvent event) {
    int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
    int pointerId = event.getPointerId(pointerIndex);

    if (event.getActionMasked() == MotionEvent.ACTION_DOWN || event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
        if(currentState == GAME_RUNNING) {
            leftArrow.handleActionDown((int)event.getX(pointerId), (int)event.getY(pointerId), pointerId);
            if(leftArrow.isTouched() && leftArrow.getPointerId() == pointerId)
                hero.setDirectionLeft();
            rightArrow.handleActionDown((int)event.getX(pointerId), (int)event.getY(pointerId), pointerId);
            if(rightArrow.isTouched() && rightArrow.getPointerId() == pointerId)
                hero.setDirectionRight();
            jumpButton.handleActionDown((int)event.getX(pointerId), (int)event.getY(pointerId), pointerId);
            if(jumpButton.isTouched() && jumpButton.getPointerId() == pointerId) 
                jumped = true;
        }
        else
            activity.finish();
    }
    if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
        if(currentState == GAME_RUNNING) {
            if(leftArrow.isTouched() && leftArrow.getPointerId() == pointerId)
                leftArrow.setTouched(false);
            if(rightArrow.isTouched() && rightArrow.getPointerId() == pointerId)
                rightArrow.setTouched(false);
            if(jumpButton.isTouched() && jumpButton.getPointerId() == pointerId) {
                jumpButton.setTouched(false);
            }
        }
    }
    if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
        int pointerCount = event.getPointerCount();
        for(int i = 0; i < pointerCount; ++i)
        {
            pointerIndex = i;
            pointerId = event.getPointerId(pointerIndex);
            if(currentState == GAME_RUNNING) {  
                leftArrow.handleActionDown((int)event.getX(pointerId), (int)event.getY(pointerId), pointerId);
                if(leftArrow.isTouched() && leftArrow.getPointerId() == pointerId) {
                    if(rightArrow.isTouched() && rightArrow.getPointerId() == pointerId)
                        rightArrow.setTouched(false);
                    hero.setDirectionLeft();
                }
                rightArrow.handleActionDown((int)event.getX(pointerId), (int)event.getY(pointerId), pointerId);
                if(rightArrow.isTouched() && rightArrow.getPointerId() == pointerId) {
                    if(leftArrow.isTouched()  && leftArrow.getPointerId() == pointerId)
                        leftArrow.setTouched(false);
                    hero.setDirectionRight();
                }
            }
        }
    }
    return true;
}

also from buttons class:
public boolean isTouched() {
    return touched;
}

public void setTouched(boolean touched) {
    this.touched = touched;
}

public int getPointerId() {
    return pointerId;
}

public void handleActionDown(int eventX, int eventY, int id) {
    if (eventX >= (x - (bitmap.getWidth()) / 2) && (eventX <= (x + (bitmap.getWidth()) / 2)))
        if (eventY >= (y - (bitmap.getWidth()) / 2) && (eventY <= (y + (bitmap.getWidth()) / 2))) {
            setTouched(true);
            pointerId = id;
        }
}

Error:
07-20 18:31:06.372: E/InputEventReceiver(5089): Exception dispatching input event.
07-20 18:31:06.377: D/AndroidRuntime(5089): Shutting down VM
07-20 18:31:06.377: W/dalvikvm(5089): threadid=1: thread exiting with uncaught     exception (group=0x411062a0)
07-20 18:31:06.432: E/AndroidRuntime(5089): FATAL EXCEPTION: main
07-20 18:31:06.432: E/AndroidRuntime(5089): java.lang.IllegalArgumentException: pointerIndex out of range
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.MotionEvent.nativeGetAxisValue(Native Method)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.MotionEvent.getX(MotionEvent.java:2148)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at pl.plumber.game.MainGamePanel.onTouchEvent(MainGamePanel.java:168)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.View.dispatchTouchEvent(View.java:7350)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2418)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2161)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2418)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2161)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2418)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2161)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2139)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1476)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.app.Activity.dispatchTouchEvent(Activity.java:2487)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2087)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.View.dispatchPointerEvent(View.java:7535)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3415)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3347)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4456)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4434)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4538)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at  android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4506)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4557)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.Choreographer.doCallbacks(Choreographer.java:555)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.Choreographer.doFrame(Choreographer.java:523)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.os.Handler.handleCallback(Handler.java:615)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.os.Handler.dispatchMessage(Handler.java:92)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.os.Looper.loop(Looper.java:137)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at android.app.ActivityThread.main(ActivityThread.java:4921)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at java.lang.reflect.Method.invokeNative(Native Method)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at java.lang.reflect.Method.invoke(Method.java:511)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
07-20 18:31:06.432: E/AndroidRuntime(5089):     at dalvik.system.NativeStart.main(Native Method)
07-20 18:31:33.652: D/dalvikvm(5089): GC_CONCURRENT freed 769K, 15% free 12606K/14727K,    paused 5ms+4ms, total 51ms

A:

The argument to MotionEvent#getX() is the pointer index, not the pointer ID. This is the source of your error.

