ScaleGestureDetector.java revision ae542ff055301a4c3c8a18e8da1739df3a771958
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; 20ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 21ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell/** 22ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Detects transformation gestures involving more than one pointer ("multitouch") 23ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * using the supplied {@link MotionEvent}s. The {@link OnScaleGestureListener} 24ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * callback will notify users when a particular gesture event has occurred. 25ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * This class should only be used with {@link MotionEvent}s reported via touch. 26ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 27ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * To use this class: 28ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <ul> 29ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>Create an instance of the {@code ScaleGestureDetector} for your 30ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link View} 31ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call 32ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link #onTouchEvent(MotionEvent)}. The methods defined in your 33ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * callback will be executed when the events occur. 34ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * </ul> 35ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @hide Pending API approval 36ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 37ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powellpublic class ScaleGestureDetector { 38ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 39ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * The listener for receiving notifications when gestures occur. 40ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If you want to listen for all the different gestures then implement 41ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * this interface. If you only want to listen for a subset it might 42ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * be easier to extend {@link SimpleOnScaleGestureListener}. 43ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 44ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * An application will receive events in the following order: 45ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <ul> 46ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>One {@link OnScaleGestureListener#onScaleBegin()} 47ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>Zero or more {@link OnScaleGestureListener#onScale()} 48ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>One {@link OnScaleGestureListener#onTransformEnd()} 49ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * </ul> 50ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 51ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public interface OnScaleGestureListener { 52ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 53ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to scaling events for a gesture in progress. 54ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Reported by pointer motion. 55ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 56ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @param detector The detector reporting the event - use this to 57ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * retrieve extended info about event state. 58ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Whether or not the detector should consider this event 59ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * as handled. If an event was not handled, the detector 60ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * will continue to accumulate movement until an event is 61ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * handled. This can be useful if an application, for example, 62ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * only wants to update scaling factors if the change is 63ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * greater than 0.01. 64ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 65ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScale(ScaleGestureDetector detector); 66ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 67ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 68ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to the beginning of a scaling gesture. Reported by 69ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * new pointers going down. 70ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 71ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @param detector The detector reporting the event - use this to 72ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * retrieve extended info about event state. 73ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Whether or not the detector should continue recognizing 74ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * this gesture. For example, if a gesture is beginning 75ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * with a focal point outside of a region where it makes 76ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * sense, onScaleBegin() may return false to ignore the 77ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * rest of the gesture. 78ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 79ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScaleBegin(ScaleGestureDetector detector); 80ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 81ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 82ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to the end of a scale gesture. Reported by existing 83ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * pointers going up. If the end of a gesture would result in a fling, 84ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link onTransformFling()} is called instead. 85ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 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. 89ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 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 } 95ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 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. 100ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} and 101ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} return 102ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@code true}. 103ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 104ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public class SimpleOnScaleGestureListener implements OnScaleGestureListener { 105ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 106ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScale(ScaleGestureDetector detector) { 107ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return true; 108ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 109ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 110ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScaleBegin(ScaleGestureDetector detector) { 111ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return true; 112ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 113ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 114ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public void onScaleEnd(ScaleGestureDetector detector) { 115ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Intentionally empty 116ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 117ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 118ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 119ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private static final float PRESSURE_THRESHOLD = 0.67f; 120ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 121ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private Context mContext; 122ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private OnScaleGestureListener mListener; 123ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private boolean mGestureInProgress; 124ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 125ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private MotionEvent mPrevEvent; 126ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private MotionEvent mCurrEvent; 127ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 128ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mFocusX; 129ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mFocusY; 130ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevFingerDiffX; 131ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevFingerDiffY; 132ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrFingerDiffX; 133ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrFingerDiffY; 134ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrLen; 135ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevLen; 136ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mScaleFactor; 137ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrPressure; 138ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevPressure; 139ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private long mTimeDelta; 140ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 141ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public ScaleGestureDetector(Context context, OnScaleGestureListener listener) { 142ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mContext = context; 143ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mListener = listener; 144ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 145ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 146ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onTouchEvent(MotionEvent event) { 147ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final int action = event.getAction(); 148ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell boolean handled = true; 149ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 150ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (!mGestureInProgress) { 151ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if ((action == MotionEvent.ACTION_POINTER_1_DOWN || 152ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell action == MotionEvent.ACTION_POINTER_2_DOWN) && 153ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell event.getPointerCount() >= 2) { 154ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // We have a new multi-finger gesture 155ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 156ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Be paranoid in case we missed an event 157ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell reset(); 158ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 159ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = MotionEvent.obtain(event); 160ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mTimeDelta = 0; 161ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 162ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 163ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mGestureInProgress = mListener.onScaleBegin(this); 164ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 165ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } else { 166ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Transform gesture in progress - attempt to handle it 167ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell switch (action) { 168ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell case MotionEvent.ACTION_POINTER_1_UP: 169ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell case MotionEvent.ACTION_POINTER_2_UP: 170ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Gesture ended 171ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 172ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 173ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Set focus point to the remaining finger 174ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell int id = (((action & MotionEvent.ACTION_POINTER_ID_MASK) 175ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell >> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0) ? 1 : 0; 176ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusX = event.getX(id); 177ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusY = event.getY(id); 178ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 179ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mListener.onScaleEnd(this); 180ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mGestureInProgress = false; 181ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 182ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell reset(); 183ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell break; 184ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 185ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell case MotionEvent.ACTION_CANCEL: 186ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mListener.onScaleEnd(this); 187ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mGestureInProgress = false; 188ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 189ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell reset(); 190ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell break; 191ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 192ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell case MotionEvent.ACTION_MOVE: 193ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 194ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 195ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Only accept the event if our relative pressure is within 196ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // a certain limit - this can help filter shaky data as a 197ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // finger is lifted. 198ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) { 199ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final boolean updatePrevious = mListener.onScale(this); 200ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 201ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (updatePrevious) { 202ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent.recycle(); 203ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = MotionEvent.obtain(event); 204ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 205ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 206ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell break; 207ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 208ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 209ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return handled; 210ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 211ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 212ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private void setContext(MotionEvent curr) { 213ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrEvent != null) { 214ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent.recycle(); 215ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 216ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent = MotionEvent.obtain(curr); 217ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 218ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrLen = -1; 219ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevLen = -1; 220ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mScaleFactor = -1; 221ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 222ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final MotionEvent prev = mPrevEvent; 223ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 224ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float px0 = prev.getX(0); 225ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float py0 = prev.getY(0); 226ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float px1 = prev.getX(1); 227ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float py1 = prev.getY(1); 228ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cx0 = curr.getX(0); 229ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cy0 = curr.getY(0); 230ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cx1 = curr.getX(1); 231ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cy1 = curr.getY(1); 232ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 233ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvx = px1 - px0; 234ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvy = py1 - py0; 235ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvx = cx1 - cx0; 236ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvy = cy1 - cy0; 237ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevFingerDiffX = pvx; 238ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevFingerDiffY = pvy; 239ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrFingerDiffX = cvx; 240ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrFingerDiffY = cvy; 241ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 242ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusX = cx0 + cvx * 0.5f; 243ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusY = cy0 + cvy * 0.5f; 244ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mTimeDelta = curr.getEventTime() - prev.getEventTime(); 245ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrPressure = curr.getPressure(0) + curr.getPressure(1); 246ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevPressure = prev.getPressure(0) + prev.getPressure(1); 247ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 248ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 249ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private void reset() { 250ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mPrevEvent != null) { 251ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent.recycle(); 252ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = null; 253ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 254ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrEvent != null) { 255ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent.recycle(); 256ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent = null; 257ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 258ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 259ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 260ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 261ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Returns {@code true} if a two-finger scale gesture is in progress. 262ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return {@code true} if a scale gesture is in progress, {@code false} otherwise. 263ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 264ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean isInProgress() { 265ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mGestureInProgress; 266ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 267ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 268ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 269ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Get the X coordinate of the current gesture's focal point. 270ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is in progress, the focal point is directly between 271ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * the two pointers forming the gesture. 272ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is ending, the focal point is the location of the 273ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * remaining pointer on the screen. 274ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If {@link isInProgress()} would return false, the result of this 275ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * function is undefined. 276ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 277ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return X coordinate of the focal point in pixels. 278ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 279ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getFocusX() { 280ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mFocusX; 281ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 282ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 283ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 284ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Get the Y coordinate of the current gesture's focal point. 285ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is in progress, the focal point is directly between 286ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * the two pointers forming the gesture. 287ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is ending, the focal point is the location of the 288ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * remaining pointer on the screen. 289ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If {@link isInProgress()} would return false, the result of this 290ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * function is undefined. 291ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 292ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Y coordinate of the focal point in pixels. 293ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 294ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getFocusY() { 295ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mFocusY; 296ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 297ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 298ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 299ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the current distance between the two pointers forming the 300ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * gesture in progress. 301ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 302ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Distance between pointers in pixels. 303ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 304ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getCurrentSpan() { 305ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrLen == -1) { 306ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvx = mCurrFingerDiffX; 307ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvy = mCurrFingerDiffY; 308ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrLen = (float)Math.sqrt(cvx*cvx + cvy*cvy); 309ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 310ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mCurrLen; 311ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 312ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 313ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 314ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the previous distance between the two pointers forming the 315ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * gesture in progress. 316ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 317ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Previous distance between pointers in pixels. 318ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 319ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getPreviousSpan() { 320ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mPrevLen == -1) { 321ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvx = mPrevFingerDiffX; 322ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvy = mPrevFingerDiffY; 323ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevLen = (float)Math.sqrt(pvx*pvx + pvy*pvy); 324ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 325ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mPrevLen; 326ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 327ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 328ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 329ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the scaling factor from the previous scale event to the current 330ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * event. This value is defined as 331ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * ({@link getCurrentSpan()} / {@link getPreviousSpan()}). 332ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 333ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return The current scaling factor. 334ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 335ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getScaleFactor() { 336ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mScaleFactor == -1) { 337ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mScaleFactor = getCurrentSpan() / getPreviousSpan(); 338ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 339ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mScaleFactor; 340ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 341ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 342ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 343ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the time difference in milliseconds between the previous 344ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * accepted scaling event and the current scaling event. 345ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 346ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Time difference since the last scaling event in milliseconds. 347ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 348ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public long getTimeDelta() { 349ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mTimeDelta; 350ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 351ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 352ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 353ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the event time of the current event being processed. 354ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * 355ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Current event time in milliseconds. 356ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 357ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public long getEventTime() { 358ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mCurrEvent.getEventTime(); 359ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 360ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell} 361