Home | History | Annotate | Download | only in android
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.backends.android;
     18 
     19 import android.content.Context;
     20 import android.view.MotionEvent;
     21 
     22 import com.badlogic.gdx.Gdx;
     23 import com.badlogic.gdx.Input.Buttons;
     24 import com.badlogic.gdx.backends.android.AndroidInput.TouchEvent;
     25 
     26 /** Multitouch handler for devices running Android >= 2.0. If device is capable of (fake) multitouch this will report additional
     27  * pointers.
     28  *
     29  * @author badlogicgames (at) gmail.com */
     30 public class AndroidMultiTouchHandler implements AndroidTouchHandler {
     31 	public void onTouch (MotionEvent event, AndroidInput input) {
     32 		final int action = event.getAction() & MotionEvent.ACTION_MASK;
     33 		int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
     34 		int pointerId = event.getPointerId(pointerIndex);
     35 
     36 		int x = 0, y = 0;
     37 		int realPointerIndex = 0;
     38 		int button = Buttons.LEFT;
     39 
     40 		long timeStamp = System.nanoTime();
     41 		synchronized (input) {
     42 			switch (action) {
     43 			case MotionEvent.ACTION_DOWN:
     44 			case MotionEvent.ACTION_POINTER_DOWN:
     45 				realPointerIndex = input.getFreePointerIndex(); // get a free pointer index as reported by Input.getX() etc.
     46 				if (realPointerIndex >= AndroidInput.NUM_TOUCHES) break;
     47 				input.realId[realPointerIndex] = pointerId;
     48 				x = (int)event.getX(pointerIndex);
     49 				y = (int)event.getY(pointerIndex);
     50 				if (android.os.Build.VERSION.SDK_INT >= 14) button = toGdxButton(event.getButtonState());
     51 				if (button != -1) postTouchEvent(input, TouchEvent.TOUCH_DOWN, x, y, realPointerIndex, button, timeStamp);
     52 				input.touchX[realPointerIndex] = x;
     53 				input.touchY[realPointerIndex] = y;
     54 				input.deltaX[realPointerIndex] = 0;
     55 				input.deltaY[realPointerIndex] = 0;
     56 				input.touched[realPointerIndex] = (button != -1);
     57 				input.button[realPointerIndex] = button;
     58 				break;
     59 
     60 			case MotionEvent.ACTION_UP:
     61 			case MotionEvent.ACTION_POINTER_UP:
     62 			case MotionEvent.ACTION_OUTSIDE:
     63 			case MotionEvent.ACTION_CANCEL:
     64 				realPointerIndex = input.lookUpPointerIndex(pointerId);
     65 				if (realPointerIndex == -1) break;
     66 				if (realPointerIndex >= AndroidInput.NUM_TOUCHES) break;
     67 				input.realId[realPointerIndex] = -1;
     68 				x = (int)event.getX(pointerIndex);
     69 				y = (int)event.getY(pointerIndex);
     70 				button = input.button[realPointerIndex];
     71 				if (button != -1) postTouchEvent(input, TouchEvent.TOUCH_UP, x, y, realPointerIndex, button, timeStamp);
     72 				input.touchX[realPointerIndex] = x;
     73 				input.touchY[realPointerIndex] = y;
     74 				input.deltaX[realPointerIndex] = 0;
     75 				input.deltaY[realPointerIndex] = 0;
     76 				input.touched[realPointerIndex] = false;
     77 				input.button[realPointerIndex] = 0;
     78 				break;
     79 
     80 			case MotionEvent.ACTION_MOVE:
     81 				int pointerCount = event.getPointerCount();
     82 				for (int i = 0; i < pointerCount; i++) {
     83 					pointerIndex = i;
     84 					pointerId = event.getPointerId(pointerIndex);
     85 					x = (int)event.getX(pointerIndex);
     86 					y = (int)event.getY(pointerIndex);
     87 					realPointerIndex = input.lookUpPointerIndex(pointerId);
     88 					if (realPointerIndex == -1) continue;
     89 					if (realPointerIndex >= AndroidInput.NUM_TOUCHES) break;
     90 					button = input.button[realPointerIndex];
     91 					if (button != -1)
     92 						postTouchEvent(input, TouchEvent.TOUCH_DRAGGED, x, y, realPointerIndex, button, timeStamp);
     93 					else
     94 						postTouchEvent(input, TouchEvent.TOUCH_MOVED, x, y, realPointerIndex, 0, timeStamp);
     95 					input.deltaX[realPointerIndex] = x - input.touchX[realPointerIndex];
     96 					input.deltaY[realPointerIndex] = y - input.touchY[realPointerIndex];
     97 					input.touchX[realPointerIndex] = x;
     98 					input.touchY[realPointerIndex] = y;
     99 				}
    100 				break;
    101 			}
    102 		}
    103 		Gdx.app.getGraphics().requestRendering();
    104 	}
    105 
    106 	private void logAction (int action, int pointer) {
    107 		String actionStr = "";
    108 		if (action == MotionEvent.ACTION_DOWN)
    109 			actionStr = "DOWN";
    110 		else if (action == MotionEvent.ACTION_POINTER_DOWN)
    111 			actionStr = "POINTER DOWN";
    112 		else if (action == MotionEvent.ACTION_UP)
    113 			actionStr = "UP";
    114 		else if (action == MotionEvent.ACTION_POINTER_UP)
    115 			actionStr = "POINTER UP";
    116 		else if (action == MotionEvent.ACTION_OUTSIDE)
    117 			actionStr = "OUTSIDE";
    118 		else if (action == MotionEvent.ACTION_CANCEL)
    119 			actionStr = "CANCEL";
    120 		else if (action == MotionEvent.ACTION_MOVE)
    121 			actionStr = "MOVE";
    122 		else
    123 			actionStr = "UNKNOWN (" + action + ")";
    124 		Gdx.app.log("AndroidMultiTouchHandler", "action " + actionStr + ", Android pointer id: " + pointer);
    125 	}
    126 
    127 	private int toGdxButton (int button) {
    128 		if (button == 0 || button == 1) return Buttons.LEFT;
    129 		if (button == 2) return Buttons.RIGHT;
    130 		if (button == 4) return Buttons.MIDDLE;
    131 		if (button == 8) return Buttons.BACK;
    132 		if (button == 16) return Buttons.FORWARD;
    133 		return -1;
    134 	}
    135 
    136 	private void postTouchEvent (AndroidInput input, int type, int x, int y, int pointer, int button, long timeStamp) {
    137 		TouchEvent event = input.usedTouchEvents.obtain();
    138 		event.timeStamp = timeStamp;
    139 		event.pointer = pointer;
    140 		event.x = x;
    141 		event.y = y;
    142 		event.type = type;
    143 		event.button = button;
    144 		input.touchEvents.add(event);
    145 	}
    146 
    147 	public boolean supportsMultitouch (Context activity) {
    148 		return activity.getPackageManager().hasSystemFeature("android.hardware.touchscreen.multitouch");
    149 	}
    150 }
    151