ScaleGestureDetector.java revision 47c41e807e36999e4d0d2072e41a82bc45655ff2
1ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell/* 2ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Copyright (C) 2010 The Android Open Source Project 3ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 4ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 5ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * you may not use this file except in compliance with the License. 6ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * You may obtain a copy of the License at 7ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 8ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * http://www.apache.org/licenses/LICENSE-2.0 9ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 10ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Unless required by applicable law or agreed to in writing, software 11ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * distributed under the License is distributed on an "AS IS" BASIS, 12ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * See the License for the specific language governing permissions and 14ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * limitations under the License. 15ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 16ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 17ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powellpackage android.view; 18ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 19ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powellimport android.content.Context; 20380b525220955ce4e4df8943b89082c7443ebfddAdam Powellimport android.util.DisplayMetrics; 21346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powellimport android.util.FloatMath; 22ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 23ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell/** 24ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Detects transformation gestures involving more than one pointer ("multitouch") 25ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * using the supplied {@link MotionEvent}s. The {@link OnScaleGestureListener} 26ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * callback will notify users when a particular gesture event has occurred. 27ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * This class should only be used with {@link MotionEvent}s reported via touch. 2847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 29ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * To use this class: 30ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <ul> 31ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>Create an instance of the {@code ScaleGestureDetector} for your 32ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link View} 33ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call 34ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link #onTouchEvent(MotionEvent)}. The methods defined in your 35ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * callback will be executed when the events occur. 36ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * </ul> 37ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 38ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powellpublic class ScaleGestureDetector { 39ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 40ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * The listener for receiving notifications when gestures occur. 41ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If you want to listen for all the different gestures then implement 42ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * this interface. If you only want to listen for a subset it might 43ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * be easier to extend {@link SimpleOnScaleGestureListener}. 4447c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 45ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * An application will receive events in the following order: 46ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <ul> 47ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * <li>One {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} 48ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * <li>Zero or more {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} 49ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * <li>One {@link OnScaleGestureListener#onScaleEnd(ScaleGestureDetector)} 50ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * </ul> 51ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 52ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public interface OnScaleGestureListener { 53ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 54ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to scaling events for a gesture in progress. 55ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Reported by pointer motion. 5647c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 57ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @param detector The detector reporting the event - use this to 58ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * retrieve extended info about event state. 59ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Whether or not the detector should consider this event 60ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * as handled. If an event was not handled, the detector 61ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * will continue to accumulate movement until an event is 62ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * handled. This can be useful if an application, for example, 63ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * only wants to update scaling factors if the change is 64ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * greater than 0.01. 65ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 66ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScale(ScaleGestureDetector detector); 67ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 68ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 69ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to the beginning of a scaling gesture. Reported by 70ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * new pointers going down. 7147c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 72ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @param detector The detector reporting the event - use this to 73ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * retrieve extended info about event state. 74ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Whether or not the detector should continue recognizing 75ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * this gesture. For example, if a gesture is beginning 76ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * with a focal point outside of a region where it makes 77ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * sense, onScaleBegin() may return false to ignore the 78ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * rest of the gesture. 79ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 80ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScaleBegin(ScaleGestureDetector detector); 81ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 82ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 83ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to the end of a scale gesture. Reported by existing 84216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell * pointers going up. 8547c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 86ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Once a scale has ended, {@link ScaleGestureDetector#getFocusX()} 87ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * and {@link ScaleGestureDetector#getFocusY()} will return the location 88ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * of the pointer remaining on the screen. 8947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 90ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @param detector The detector reporting the event - use this to 91ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * retrieve extended info about event state. 92ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 93ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public void onScaleEnd(ScaleGestureDetector detector); 94ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 9547c41e807e36999e4d0d2072e41a82bc45655ff2Erik 96ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 97ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * A convenience class to extend when you only want to listen for a subset 98ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * of scaling-related events. This implements all methods in 99ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link OnScaleGestureListener} but does nothing. 100346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} returns 101346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * {@code false} so that a subclass can retrieve the accumulated scale 102346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * factor in an overridden onScaleEnd. 103346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} returns 10447c41e807e36999e4d0d2072e41a82bc45655ff2Erik * {@code true}. 105ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 106216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell public static class SimpleOnScaleGestureListener implements OnScaleGestureListener { 107ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 108ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScale(ScaleGestureDetector detector) { 109346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell return false; 110ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 111ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 112ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScaleBegin(ScaleGestureDetector detector) { 113ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return true; 114ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 115ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 116ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public void onScaleEnd(ScaleGestureDetector detector) { 117ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Intentionally empty 118ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 119ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 120ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 121346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell /** 122346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * This value is the threshold ratio between our previous combined pressure 123346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * and the current combined pressure. We will only fire an onScale event if 124346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * the computed ratio between the current and previous event pressures is 125346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * greater than this value. When pressure decreases rapidly between events 126346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * the position values can often be imprecise, as it usually indicates 127346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * that the user is in the process of lifting a pointer off of the device. 128346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * Its value was tuned experimentally. 129346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell */ 130ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private static final float PRESSURE_THRESHOLD = 0.67f; 131ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 132346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell private final Context mContext; 133346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell private final OnScaleGestureListener mListener; 134ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private boolean mGestureInProgress; 135ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 136ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private MotionEvent mPrevEvent; 137ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private MotionEvent mCurrEvent; 138ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 139ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mFocusX; 140ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mFocusY; 141ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevFingerDiffX; 142ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevFingerDiffY; 143ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrFingerDiffX; 144ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrFingerDiffY; 145ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrLen; 146ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevLen; 147ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mScaleFactor; 148ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrPressure; 149ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevPressure; 150ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private long mTimeDelta; 15147c41e807e36999e4d0d2072e41a82bc45655ff2Erik 152346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell private final float mEdgeSlop; 153380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private float mRightSlopEdge; 154380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private float mBottomSlopEdge; 155380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private boolean mSloppyGesture; 156ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 157ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public ScaleGestureDetector(Context context, OnScaleGestureListener listener) { 158380b525220955ce4e4df8943b89082c7443ebfddAdam Powell ViewConfiguration config = ViewConfiguration.get(context); 159ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mContext = context; 160ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mListener = listener; 161380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mEdgeSlop = config.getScaledEdgeSlop(); 162ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 163ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 164ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onTouchEvent(MotionEvent event) { 165ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final int action = event.getAction(); 166ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell boolean handled = true; 167ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 168ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (!mGestureInProgress) { 169f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell switch (action & MotionEvent.ACTION_MASK) { 170f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell case MotionEvent.ACTION_POINTER_DOWN: { 171ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // We have a new multi-finger gesture 172380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 173d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba // as orientation can change, query the metrics in touch down 174d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); 175d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba mRightSlopEdge = metrics.widthPixels - mEdgeSlop; 176d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba mBottomSlopEdge = metrics.heightPixels - mEdgeSlop; 177d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba 178ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Be paranoid in case we missed an event 179ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell reset(); 180380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 181ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = MotionEvent.obtain(event); 182ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mTimeDelta = 0; 183380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 184ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 185380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 186380b525220955ce4e4df8943b89082c7443ebfddAdam Powell // Check if we have a sloppy gesture. If so, delay 187380b525220955ce4e4df8943b89082c7443ebfddAdam Powell // the beginning of the gesture until we're sure that's 188380b525220955ce4e4df8943b89082c7443ebfddAdam Powell // what the user wanted. Sloppy gestures can happen if the 189380b525220955ce4e4df8943b89082c7443ebfddAdam Powell // edge of the user's hand is touching the screen, for example. 190380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float edgeSlop = mEdgeSlop; 191380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float rightSlop = mRightSlopEdge; 192380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float bottomSlop = mBottomSlopEdge; 193380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float x0 = event.getRawX(); 194380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float y0 = event.getRawY(); 195380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float x1 = getRawX(event, 1); 196380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float y1 = getRawY(event, 1); 197380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 1988f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop 1998f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba || x0 > rightSlop || y0 > bottomSlop; 2008f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop 2018f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba || x1 > rightSlop || y1 > bottomSlop; 202380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 203f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell if (p0sloppy && p1sloppy) { 2048f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba mFocusX = -1; 2058f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba mFocusY = -1; 2068f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba mSloppyGesture = true; 2078f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba } else if (p0sloppy) { 208380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mFocusX = event.getX(1); 209380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mFocusY = event.getY(1); 210380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mSloppyGesture = true; 211380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } else if (p1sloppy) { 212380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mFocusX = event.getX(0); 213380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mFocusY = event.getY(0); 214380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mSloppyGesture = true; 215380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } else { 216380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mGestureInProgress = mListener.onScaleBegin(this); 217380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 218f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } 219f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell break; 22047c41e807e36999e4d0d2072e41a82bc45655ff2Erik 221f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell case MotionEvent.ACTION_MOVE: 222f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell if (mSloppyGesture) { 223f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell // Initiate sloppy gestures if we've moved outside of the slop area. 224f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float edgeSlop = mEdgeSlop; 225f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float rightSlop = mRightSlopEdge; 226f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float bottomSlop = mBottomSlopEdge; 227f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float x0 = event.getRawX(); 228f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float y0 = event.getRawY(); 229f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float x1 = getRawX(event, 1); 230f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float y1 = getRawY(event, 1); 231380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 232f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop 233f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell || x0 > rightSlop || y0 > bottomSlop; 234f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop 235f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell || x1 > rightSlop || y1 > bottomSlop; 236380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 237f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell if(p0sloppy && p1sloppy) { 238f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusX = -1; 239f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusY = -1; 240f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } else if (p0sloppy) { 241f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusX = event.getX(1); 242f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusY = event.getY(1); 243f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } else if (p1sloppy) { 244f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusX = event.getX(0); 245f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusY = event.getY(0); 246f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } else { 247f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mSloppyGesture = false; 248f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mGestureInProgress = mListener.onScaleBegin(this); 249f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } 250f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } 251f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell break; 25247c41e807e36999e4d0d2072e41a82bc45655ff2Erik 253f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell case MotionEvent.ACTION_POINTER_UP: 254f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell if (mSloppyGesture) { 255f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell // Set focus point to the remaining finger 256f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK) 257f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0; 258f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusX = event.getX(id); 259f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusY = event.getY(id); 260380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 261f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell break; 262ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 263ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } else { 264ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Transform gesture in progress - attempt to handle it 265f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell switch (action & MotionEvent.ACTION_MASK) { 266f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell case MotionEvent.ACTION_POINTER_UP: 267ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Gesture ended 268ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 269380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 270ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Set focus point to the remaining finger 271f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK) 272f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0; 273ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusX = event.getX(id); 274ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusY = event.getY(id); 275380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 276380b525220955ce4e4df8943b89082c7443ebfddAdam Powell if (!mSloppyGesture) { 277380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mListener.onScaleEnd(this); 278380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 279ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 280ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell reset(); 281ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell break; 282ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 283ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell case MotionEvent.ACTION_CANCEL: 284380b525220955ce4e4df8943b89082c7443ebfddAdam Powell if (!mSloppyGesture) { 285380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mListener.onScaleEnd(this); 286380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 287ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 288ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell reset(); 289ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell break; 290ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 291ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell case MotionEvent.ACTION_MOVE: 292ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 293ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 294ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Only accept the event if our relative pressure is within 295ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // a certain limit - this can help filter shaky data as a 296ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // finger is lifted. 297ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) { 298ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final boolean updatePrevious = mListener.onScale(this); 299ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 300ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (updatePrevious) { 301ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent.recycle(); 302ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = MotionEvent.obtain(event); 303ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 304ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 305ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell break; 306ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 307ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 308ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return handled; 309ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 31047c41e807e36999e4d0d2072e41a82bc45655ff2Erik 311380b525220955ce4e4df8943b89082c7443ebfddAdam Powell /** 31247c41e807e36999e4d0d2072e41a82bc45655ff2Erik * MotionEvent has no getRawX(int) method; simulate it pending future API approval. 313380b525220955ce4e4df8943b89082c7443ebfddAdam Powell */ 314380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private static float getRawX(MotionEvent event, int pointerIndex) { 3159bccdb7d5c93e350337e707bc6edf3cd017b8f96Adam Powell float offset = event.getRawX() - event.getX(); 316380b525220955ce4e4df8943b89082c7443ebfddAdam Powell return event.getX(pointerIndex) + offset; 317380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 31847c41e807e36999e4d0d2072e41a82bc45655ff2Erik 319380b525220955ce4e4df8943b89082c7443ebfddAdam Powell /** 32047c41e807e36999e4d0d2072e41a82bc45655ff2Erik * MotionEvent has no getRawY(int) method; simulate it pending future API approval. 321380b525220955ce4e4df8943b89082c7443ebfddAdam Powell */ 322380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private static float getRawY(MotionEvent event, int pointerIndex) { 3239bccdb7d5c93e350337e707bc6edf3cd017b8f96Adam Powell float offset = event.getRawY() - event.getY(); 324380b525220955ce4e4df8943b89082c7443ebfddAdam Powell return event.getY(pointerIndex) + offset; 325380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 326ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 327ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private void setContext(MotionEvent curr) { 328ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrEvent != null) { 329ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent.recycle(); 330ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 331ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent = MotionEvent.obtain(curr); 332ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 333ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrLen = -1; 334ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevLen = -1; 335ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mScaleFactor = -1; 336ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 337ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final MotionEvent prev = mPrevEvent; 338ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 339ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float px0 = prev.getX(0); 340ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float py0 = prev.getY(0); 341ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float px1 = prev.getX(1); 342ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float py1 = prev.getY(1); 343ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cx0 = curr.getX(0); 344ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cy0 = curr.getY(0); 345ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cx1 = curr.getX(1); 346ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cy1 = curr.getY(1); 347ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 348ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvx = px1 - px0; 349ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvy = py1 - py0; 350ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvx = cx1 - cx0; 351ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvy = cy1 - cy0; 352ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevFingerDiffX = pvx; 353ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevFingerDiffY = pvy; 354ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrFingerDiffX = cvx; 355ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrFingerDiffY = cvy; 356ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 357ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusX = cx0 + cvx * 0.5f; 358ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusY = cy0 + cvy * 0.5f; 359ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mTimeDelta = curr.getEventTime() - prev.getEventTime(); 360ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrPressure = curr.getPressure(0) + curr.getPressure(1); 361ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevPressure = prev.getPressure(0) + prev.getPressure(1); 362ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 363ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 364ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private void reset() { 365ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mPrevEvent != null) { 366ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent.recycle(); 367ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = null; 368ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 369ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrEvent != null) { 370ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent.recycle(); 371ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent = null; 372ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 373380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mSloppyGesture = false; 374380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mGestureInProgress = false; 375ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 376ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 377ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 378ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Returns {@code true} if a two-finger scale gesture is in progress. 379ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return {@code true} if a scale gesture is in progress, {@code false} otherwise. 380ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 381ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean isInProgress() { 382ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mGestureInProgress; 383ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 384ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 385ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 386ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Get the X coordinate of the current gesture's focal point. 387ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is in progress, the focal point is directly between 388ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * the two pointers forming the gesture. 389ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is ending, the focal point is the location of the 390ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * remaining pointer on the screen. 391ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * If {@link #isInProgress()} would return false, the result of this 392ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * function is undefined. 39347c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 394ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return X coordinate of the focal point in pixels. 395ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 396ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getFocusX() { 397ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mFocusX; 398ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 399ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 400ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 401ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Get the Y coordinate of the current gesture's focal point. 402ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is in progress, the focal point is directly between 403ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * the two pointers forming the gesture. 404ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is ending, the focal point is the location of the 405ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * remaining pointer on the screen. 406ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * If {@link #isInProgress()} would return false, the result of this 407ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * function is undefined. 40847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 409ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Y coordinate of the focal point in pixels. 410ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 411ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getFocusY() { 412ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mFocusY; 413ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 414ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 415ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 416ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the current distance between the two pointers forming the 417ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * gesture in progress. 41847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 419ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Distance between pointers in pixels. 420ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 421ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getCurrentSpan() { 422ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrLen == -1) { 423ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvx = mCurrFingerDiffX; 424ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvy = mCurrFingerDiffY; 425346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell mCurrLen = FloatMath.sqrt(cvx*cvx + cvy*cvy); 426ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 427ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mCurrLen; 428ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 429ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 430ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 43147c41e807e36999e4d0d2072e41a82bc45655ff2Erik * Return the current x distance between the two pointers forming the 43247c41e807e36999e4d0d2072e41a82bc45655ff2Erik * gesture in progress. 43347c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 43447c41e807e36999e4d0d2072e41a82bc45655ff2Erik * @return Distance between pointers in pixels. 43547c41e807e36999e4d0d2072e41a82bc45655ff2Erik */ 43647c41e807e36999e4d0d2072e41a82bc45655ff2Erik public float getCurrentSpanX() { 43747c41e807e36999e4d0d2072e41a82bc45655ff2Erik return mCurrFingerDiffX; 43847c41e807e36999e4d0d2072e41a82bc45655ff2Erik } 43947c41e807e36999e4d0d2072e41a82bc45655ff2Erik 44047c41e807e36999e4d0d2072e41a82bc45655ff2Erik /** 44147c41e807e36999e4d0d2072e41a82bc45655ff2Erik * Return the current y distance between the two pointers forming the 44247c41e807e36999e4d0d2072e41a82bc45655ff2Erik * gesture in progress. 44347c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 44447c41e807e36999e4d0d2072e41a82bc45655ff2Erik * @return Distance between pointers in pixels. 44547c41e807e36999e4d0d2072e41a82bc45655ff2Erik */ 44647c41e807e36999e4d0d2072e41a82bc45655ff2Erik public float getCurrentSpanY() { 44747c41e807e36999e4d0d2072e41a82bc45655ff2Erik return mCurrFingerDiffY; 44847c41e807e36999e4d0d2072e41a82bc45655ff2Erik } 44947c41e807e36999e4d0d2072e41a82bc45655ff2Erik 45047c41e807e36999e4d0d2072e41a82bc45655ff2Erik /** 451ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the previous distance between the two pointers forming the 452ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * gesture in progress. 45347c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 454ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Previous distance between pointers in pixels. 455ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 456ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getPreviousSpan() { 457ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mPrevLen == -1) { 458ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvx = mPrevFingerDiffX; 459ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvy = mPrevFingerDiffY; 460346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell mPrevLen = FloatMath.sqrt(pvx*pvx + pvy*pvy); 461ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 462ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mPrevLen; 463ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 464ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 465ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 46647c41e807e36999e4d0d2072e41a82bc45655ff2Erik * Return the previous x distance between the two pointers forming the 46747c41e807e36999e4d0d2072e41a82bc45655ff2Erik * gesture in progress. 46847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 46947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * @return Previous distance between pointers in pixels. 47047c41e807e36999e4d0d2072e41a82bc45655ff2Erik */ 47147c41e807e36999e4d0d2072e41a82bc45655ff2Erik public float getPreviousSpanX() { 47247c41e807e36999e4d0d2072e41a82bc45655ff2Erik return mPrevFingerDiffX; 47347c41e807e36999e4d0d2072e41a82bc45655ff2Erik } 47447c41e807e36999e4d0d2072e41a82bc45655ff2Erik 47547c41e807e36999e4d0d2072e41a82bc45655ff2Erik /** 47647c41e807e36999e4d0d2072e41a82bc45655ff2Erik * Return the previous y distance between the two pointers forming the 47747c41e807e36999e4d0d2072e41a82bc45655ff2Erik * gesture in progress. 47847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 47947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * @return Previous distance between pointers in pixels. 48047c41e807e36999e4d0d2072e41a82bc45655ff2Erik */ 48147c41e807e36999e4d0d2072e41a82bc45655ff2Erik public float getPreviousSpanY() { 48247c41e807e36999e4d0d2072e41a82bc45655ff2Erik return mPrevFingerDiffY; 48347c41e807e36999e4d0d2072e41a82bc45655ff2Erik } 48447c41e807e36999e4d0d2072e41a82bc45655ff2Erik 48547c41e807e36999e4d0d2072e41a82bc45655ff2Erik /** 486ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the scaling factor from the previous scale event to the current 487ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * event. This value is defined as 488ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * ({@link #getCurrentSpan()} / {@link #getPreviousSpan()}). 48947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 490ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return The current scaling factor. 491ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 492ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getScaleFactor() { 493ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mScaleFactor == -1) { 494ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mScaleFactor = getCurrentSpan() / getPreviousSpan(); 495ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 496ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mScaleFactor; 497ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 49847c41e807e36999e4d0d2072e41a82bc45655ff2Erik 499ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 500ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the time difference in milliseconds between the previous 501ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * accepted scaling event and the current scaling event. 50247c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 503ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Time difference since the last scaling event in milliseconds. 504ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 505ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public long getTimeDelta() { 506ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mTimeDelta; 507ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 50847c41e807e36999e4d0d2072e41a82bc45655ff2Erik 509ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 510ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the event time of the current event being processed. 51147c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 512ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Current event time in milliseconds. 513ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 514ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public long getEventTime() { 515ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mCurrEvent.getEventTime(); 516ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 517ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell} 518