18fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang/* 28fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * Copyright (C) 2012 The Android Open Source Project 38fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * 48fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * Licensed under the Apache License, Version 2.0 (the "License"); 58fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * you may not use this file except in compliance with the License. 68fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * You may obtain a copy of the License at 78fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * 88fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * http://www.apache.org/licenses/LICENSE-2.0 98fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * 108fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * Unless required by applicable law or agreed to in writing, software 118fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * distributed under the License is distributed on an "AS IS" BASIS, 128fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * See the License for the specific language governing permissions and 148fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang * limitations under the License. 158fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang */ 168fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Changpackage com.android.gallery3d.util; 178fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 188fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Changimport android.annotation.TargetApi; 198fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Changimport android.graphics.Matrix; 208fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Changimport android.view.MotionEvent; 218fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Changimport android.view.MotionEvent.PointerCoords; 228fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 238fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Changimport com.android.gallery3d.common.ApiHelper; 248fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 258fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Changpublic final class MotionEventHelper { 268fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang private MotionEventHelper() {} 278fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 288fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang public static MotionEvent transformEvent(MotionEvent e, Matrix m) { 298fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang // We try to use the new transform method if possible because it uses 308fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang // less memory. 318fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang if (ApiHelper.HAS_MOTION_EVENT_TRANSFORM) { 328fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang return transformEventNew(e, m); 338fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } else { 348fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang return transformEventOld(e, m); 358fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 368fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 378fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 388fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) 398fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang private static MotionEvent transformEventNew(MotionEvent e, Matrix m) { 4037ba3d7b5953decbb7cc21f74cd61ceed12b199aWu-cheng Li MotionEvent newEvent = MotionEvent.obtain(e); 4137ba3d7b5953decbb7cc21f74cd61ceed12b199aWu-cheng Li newEvent.transform(m); 4237ba3d7b5953decbb7cc21f74cd61ceed12b199aWu-cheng Li return newEvent; 438fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 448fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 458fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang // This is copied from Input.cpp in the android framework. 468fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang private static MotionEvent transformEventOld(MotionEvent e, Matrix m) { 478fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang long downTime = e.getDownTime(); 488fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang long eventTime = e.getEventTime(); 498fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int action = e.getAction(); 508fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int pointerCount = e.getPointerCount(); 518fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int[] pointerIds = getPointerIds(e); 528fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang PointerCoords[] pointerCoords = getPointerCoords(e); 538fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int metaState = e.getMetaState(); 548fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang float xPrecision = e.getXPrecision(); 558fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang float yPrecision = e.getYPrecision(); 568fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int deviceId = e.getDeviceId(); 578fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int edgeFlags = e.getEdgeFlags(); 588fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int source = e.getSource(); 598fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int flags = e.getFlags(); 608fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 618fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang // Copy the x and y coordinates into an array, map them, and copy back. 628fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang float[] xy = new float[pointerCoords.length * 2]; 638fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang for (int i = 0; i < pointerCount;i++) { 648fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang xy[2 * i] = pointerCoords[i].x; 658fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang xy[2 * i + 1] = pointerCoords[i].y; 668fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 678fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang m.mapPoints(xy); 688fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang for (int i = 0; i < pointerCount;i++) { 698fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang pointerCoords[i].x = xy[2 * i]; 708fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang pointerCoords[i].y = xy[2 * i + 1]; 718fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang pointerCoords[i].orientation = transformAngle( 728fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang m, pointerCoords[i].orientation); 738fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 748fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 758fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang MotionEvent n = MotionEvent.obtain(downTime, eventTime, action, 768fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang pointerCount, pointerIds, pointerCoords, metaState, xPrecision, 778fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang yPrecision, deviceId, edgeFlags, source, flags); 788fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 798fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang return n; 808fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 818fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 828fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang private static int[] getPointerIds(MotionEvent e) { 838fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int n = e.getPointerCount(); 848fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int[] r = new int[n]; 858fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang for (int i = 0; i < n; i++) { 868fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang r[i] = e.getPointerId(i); 878fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 888fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang return r; 898fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 908fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 918fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang private static PointerCoords[] getPointerCoords(MotionEvent e) { 928fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang int n = e.getPointerCount(); 938fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang PointerCoords[] r = new PointerCoords[n]; 948fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang for (int i = 0; i < n; i++) { 958fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang r[i] = new PointerCoords(); 968fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang e.getPointerCoords(i, r[i]); 978fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 988fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang return r; 998fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 1008fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 1018fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang private static float transformAngle(Matrix m, float angleRadians) { 1028fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang // Construct and transform a vector oriented at the specified clockwise 1038fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang // angle from vertical. Coordinate system: down is increasing Y, right is 1048fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang // increasing X. 1058fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang float[] v = new float[2]; 1068a55d3ae7486b798e4c26eeb91993916145f3cefNeil Fuller v[0] = (float) Math.sin(angleRadians); 1078a55d3ae7486b798e4c26eeb91993916145f3cefNeil Fuller v[1] = (float) -Math.cos(angleRadians); 1088fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang m.mapVectors(v); 1098fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang 1108fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang // Derive the transformed vector's clockwise angle from vertical. 1118fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang float result = (float) Math.atan2(v[0], -v[1]); 1128fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang if (result < -Math.PI / 2) { 1138fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang result += Math.PI; 1148fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } else if (result > Math.PI / 2) { 1158fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang result -= Math.PI; 1168fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 1178fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang return result; 1188fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang } 1198fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang} 120