ScaleGestureDetector.java revision d0197f3669efda060c7ee2069ff41bd970fd6d9c
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; 220818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powellimport android.util.Log; 23ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 24ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell/** 25ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Detects transformation gestures involving more than one pointer ("multitouch") 26ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * using the supplied {@link MotionEvent}s. The {@link OnScaleGestureListener} 27ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * callback will notify users when a particular gesture event has occurred. 28ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * This class should only be used with {@link MotionEvent}s reported via touch. 2947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 30ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * To use this class: 31ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <ul> 32ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>Create an instance of the {@code ScaleGestureDetector} for your 33ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link View} 34ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call 35ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link #onTouchEvent(MotionEvent)}. The methods defined in your 36ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * callback will be executed when the events occur. 37ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * </ul> 38ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 39ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powellpublic class ScaleGestureDetector { 400818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell private static final String TAG = "ScaleGestureDetector"; 410818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell 42ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 43ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * The listener for receiving notifications when gestures occur. 44ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If you want to listen for all the different gestures then implement 45ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * this interface. If you only want to listen for a subset it might 46ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * be easier to extend {@link SimpleOnScaleGestureListener}. 4747c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 48ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * An application will receive events in the following order: 49ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * <ul> 50ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * <li>One {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} 51ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * <li>Zero or more {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} 52ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * <li>One {@link OnScaleGestureListener#onScaleEnd(ScaleGestureDetector)} 53ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * </ul> 54ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 55ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public interface OnScaleGestureListener { 56ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 57ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to scaling events for a gesture in progress. 58ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Reported by pointer motion. 5947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 60ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @param detector The detector reporting the event - use this to 61ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * retrieve extended info about event state. 62ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Whether or not the detector should consider this event 63ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * as handled. If an event was not handled, the detector 64ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * will continue to accumulate movement until an event is 65ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * handled. This can be useful if an application, for example, 66ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * only wants to update scaling factors if the change is 67ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * greater than 0.01. 68ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 69ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScale(ScaleGestureDetector detector); 70ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 71ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 72ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to the beginning of a scaling gesture. Reported by 73ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * new pointers going down. 7447c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 75ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @param detector The detector reporting the event - use this to 76ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * retrieve extended info about event state. 77ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Whether or not the detector should continue recognizing 78ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * this gesture. For example, if a gesture is beginning 79ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * with a focal point outside of a region where it makes 80ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * sense, onScaleBegin() may return false to ignore the 81ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * rest of the gesture. 82ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 83ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScaleBegin(ScaleGestureDetector detector); 84ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 85ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 86ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Responds to the end of a scale gesture. Reported by existing 87216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell * pointers going up. 8847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 89ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Once a scale has ended, {@link ScaleGestureDetector#getFocusX()} 90ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * and {@link ScaleGestureDetector#getFocusY()} will return the location 91ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * of the pointer remaining on the screen. 9247c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 93ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @param detector The detector reporting the event - use this to 94ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * retrieve extended info about event state. 95ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 96ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public void onScaleEnd(ScaleGestureDetector detector); 97ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 9847c41e807e36999e4d0d2072e41a82bc45655ff2Erik 99ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 100ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * A convenience class to extend when you only want to listen for a subset 101ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * of scaling-related events. This implements all methods in 102ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * {@link OnScaleGestureListener} but does nothing. 103346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} returns 104346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * {@code false} so that a subclass can retrieve the accumulated scale 105346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * factor in an overridden onScaleEnd. 106346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} returns 10747c41e807e36999e4d0d2072e41a82bc45655ff2Erik * {@code true}. 108ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 109216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell public static class SimpleOnScaleGestureListener implements OnScaleGestureListener { 110ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 111ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScale(ScaleGestureDetector detector) { 112346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell return false; 113ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 114ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 115ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onScaleBegin(ScaleGestureDetector detector) { 116ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return true; 117ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 118ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 119ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public void onScaleEnd(ScaleGestureDetector detector) { 120ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Intentionally empty 121ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 122ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 123ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 124346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell /** 125346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * This value is the threshold ratio between our previous combined pressure 126346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * and the current combined pressure. We will only fire an onScale event if 127346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * the computed ratio between the current and previous event pressures is 128346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * greater than this value. When pressure decreases rapidly between events 129346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * the position values can often be imprecise, as it usually indicates 130346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * that the user is in the process of lifting a pointer off of the device. 131346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell * Its value was tuned experimentally. 132346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell */ 133ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private static final float PRESSURE_THRESHOLD = 0.67f; 134ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 135346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell private final Context mContext; 136346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell private final OnScaleGestureListener mListener; 137ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private boolean mGestureInProgress; 138ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 139ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private MotionEvent mPrevEvent; 140ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private MotionEvent mCurrEvent; 141ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 142ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mFocusX; 143ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mFocusY; 144ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevFingerDiffX; 145ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevFingerDiffY; 146ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrFingerDiffX; 147ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrFingerDiffY; 148ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrLen; 149ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevLen; 150ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mScaleFactor; 151ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mCurrPressure; 152ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private float mPrevPressure; 153ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private long mTimeDelta; 15447c41e807e36999e4d0d2072e41a82bc45655ff2Erik 155346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell private final float mEdgeSlop; 156380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private float mRightSlopEdge; 157380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private float mBottomSlopEdge; 158380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private boolean mSloppyGesture; 159d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell private boolean mInvalidGesture; 160ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 161e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // Pointer IDs currently responsible for the two fingers controlling the gesture 162e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell private int mActiveId0; 163e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell private int mActiveId1; 164e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell private boolean mActive0MostRecent; 165e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 166ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public ScaleGestureDetector(Context context, OnScaleGestureListener listener) { 167380b525220955ce4e4df8943b89082c7443ebfddAdam Powell ViewConfiguration config = ViewConfiguration.get(context); 168ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mContext = context; 169ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mListener = listener; 170380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mEdgeSlop = config.getScaledEdgeSlop(); 171ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 172ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 173ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean onTouchEvent(MotionEvent event) { 174e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int action = event.getActionMasked(); 175ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell boolean handled = true; 176ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 1770818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell if (action == MotionEvent.ACTION_DOWN) { 1780818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell reset(); // Start fresh 1790818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell } 1800818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell 181d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell if (mInvalidGesture) return false; 182d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell 183ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (!mGestureInProgress) { 184e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell switch (action) { 185e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell case MotionEvent.ACTION_DOWN: { 186e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId0 = event.getPointerId(0); 187e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActive0MostRecent = true; 188e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 189e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell break; 190e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 191e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell case MotionEvent.ACTION_UP: 192e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell reset(); 193e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell break; 194e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 195f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell case MotionEvent.ACTION_POINTER_DOWN: { 196ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // We have a new multi-finger gesture 197380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 198d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba // as orientation can change, query the metrics in touch down 199d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); 200d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba mRightSlopEdge = metrics.widthPixels - mEdgeSlop; 201d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba mBottomSlopEdge = metrics.heightPixels - mEdgeSlop; 202d5ada83c719d366d3063572ca6ce5ab8918fd39bGrace Kloba 203e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (mPrevEvent != null) mPrevEvent.recycle(); 204ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = MotionEvent.obtain(event); 205ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mTimeDelta = 0; 206380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 207e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell int index1 = event.getActionIndex(); 208e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell int index0 = event.findPointerIndex(mActiveId0); 209e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId1 = event.getPointerId(index1); 2100818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell if (index0 < 0 || index0 == index1) { 2110818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell // Probably someone sending us a broken event stream. 2120818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell index0 = findNewActiveIndex(event, index0 == index1 ? -1 : mActiveId1, index0); 2130818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell mActiveId0 = event.getPointerId(index0); 2140818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell } 215e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActive0MostRecent = false; 216e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 217ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 218380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 219380b525220955ce4e4df8943b89082c7443ebfddAdam Powell // Check if we have a sloppy gesture. If so, delay 220380b525220955ce4e4df8943b89082c7443ebfddAdam Powell // the beginning of the gesture until we're sure that's 221380b525220955ce4e4df8943b89082c7443ebfddAdam Powell // what the user wanted. Sloppy gestures can happen if the 222380b525220955ce4e4df8943b89082c7443ebfddAdam Powell // edge of the user's hand is touching the screen, for example. 223380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float edgeSlop = mEdgeSlop; 224380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float rightSlop = mRightSlopEdge; 225380b525220955ce4e4df8943b89082c7443ebfddAdam Powell final float bottomSlop = mBottomSlopEdge; 226e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float x0 = getRawX(event, index0); 227e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float y0 = getRawY(event, index0); 228e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float x1 = getRawX(event, index1); 229e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float y1 = getRawY(event, index1); 230380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 2318f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop 2328f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba || x0 > rightSlop || y0 > bottomSlop; 2338f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop 2348f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba || x1 > rightSlop || y1 > bottomSlop; 235380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 236f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell if (p0sloppy && p1sloppy) { 2378f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba mFocusX = -1; 2388f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba mFocusY = -1; 2398f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba mSloppyGesture = true; 2408f9fbb0c45265a6f5da51cb3bc35362d8e5bc900Grace Kloba } else if (p0sloppy) { 241e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusX = event.getX(index1); 242e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusY = event.getY(index1); 243380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mSloppyGesture = true; 244380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } else if (p1sloppy) { 245e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusX = event.getX(index0); 246e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusY = event.getY(index0); 247380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mSloppyGesture = true; 248380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } else { 249e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mSloppyGesture = false; 250380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mGestureInProgress = mListener.onScaleBegin(this); 251380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 252f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } 253f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell break; 25447c41e807e36999e4d0d2072e41a82bc45655ff2Erik 255f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell case MotionEvent.ACTION_MOVE: 256f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell if (mSloppyGesture) { 257f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell // Initiate sloppy gestures if we've moved outside of the slop area. 258f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float edgeSlop = mEdgeSlop; 259f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float rightSlop = mRightSlopEdge; 260f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell final float bottomSlop = mBottomSlopEdge; 261e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell int index0 = event.findPointerIndex(mActiveId0); 262e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell int index1 = event.findPointerIndex(mActiveId1); 2630fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell 264e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float x0 = getRawX(event, index0); 265e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float y0 = getRawY(event, index0); 266e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float x1 = getRawX(event, index1); 267e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float y1 = getRawY(event, index1); 268380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 269f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop 270e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell || x0 > rightSlop || y0 > bottomSlop; 271f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop 272e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell || x1 > rightSlop || y1 > bottomSlop; 273e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 274e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (p0sloppy) { 275e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // Do we have a different pointer that isn't sloppy? 276e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell int index = findNewActiveIndex(event, mActiveId1, index0); 277e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (index >= 0) { 278e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell index0 = index; 279e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId0 = event.getPointerId(index); 280e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell x0 = getRawX(event, index); 281e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell y0 = getRawY(event, index); 282e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell p0sloppy = false; 283e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 284e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 285e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 286e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (p1sloppy) { 287e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // Do we have a different pointer that isn't sloppy? 288e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell int index = findNewActiveIndex(event, mActiveId0, index1); 289e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (index >= 0) { 290e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell index1 = index; 291e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId1 = event.getPointerId(index); 292e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell x1 = getRawX(event, index); 293e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell y1 = getRawY(event, index); 294e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell p1sloppy = false; 295e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 296e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 297380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 298f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell if(p0sloppy && p1sloppy) { 299f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusX = -1; 300f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mFocusY = -1; 301f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } else if (p0sloppy) { 302e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusX = event.getX(index1); 303e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusY = event.getY(index1); 304f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } else if (p1sloppy) { 305e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusX = event.getX(index0); 306e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusY = event.getY(index0); 307f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } else { 308f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mSloppyGesture = false; 309f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell mGestureInProgress = mListener.onScaleBegin(this); 310f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } 311f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell } 312f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell break; 31347c41e807e36999e4d0d2072e41a82bc45655ff2Erik 314f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell case MotionEvent.ACTION_POINTER_UP: 315f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell if (mSloppyGesture) { 316e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int pointerCount = event.getPointerCount(); 317e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int actionIndex = event.getActionIndex(); 318e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int actionId = event.getPointerId(actionIndex); 319e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 320e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (pointerCount > 2) { 321e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (actionId == mActiveId0) { 322e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex); 323e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (newIndex >= 0) mActiveId0 = event.getPointerId(newIndex); 324e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } else if (actionId == mActiveId1) { 325e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex); 326e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (newIndex >= 0) mActiveId1 = event.getPointerId(newIndex); 327e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 328e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } else { 329e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // Set focus point to the remaining finger 330e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int index = event.findPointerIndex(actionId == mActiveId0 ? 331e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId1 : mActiveId0); 332e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId0 = event.getPointerId(index); 3330818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell 334e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActive0MostRecent = true; 335e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId1 = -1; 336e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusX = event.getX(index); 337e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusY = event.getY(index); 338e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 339380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 340f5bcc6addd9c1f8f6bb8b8626540d003b3f964faAdam Powell break; 341ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 342ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } else { 343ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Transform gesture in progress - attempt to handle it 344e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell switch (action) { 345e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell case MotionEvent.ACTION_POINTER_DOWN: { 346e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // End the old gesture and begin a new one with the most recent two fingers. 347e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mListener.onScaleEnd(this); 348e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int oldActive0 = mActiveId0; 349e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int oldActive1 = mActiveId1; 350e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell reset(); 351e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 352e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mPrevEvent = MotionEvent.obtain(event); 353e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId0 = mActive0MostRecent ? oldActive0 : oldActive1; 354e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId1 = event.getPointerId(event.getActionIndex()); 355e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActive0MostRecent = false; 356e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 3570818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell int index0 = event.findPointerIndex(mActiveId0); 3580818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell if (index0 < 0 || mActiveId0 == mActiveId1) { 3590818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell // Probably someone sending us a broken event stream. 3600818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell Log.e(TAG, "Got " + MotionEvent.actionToString(action) + 3610818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell " with bad state while a gesture was in progress. " + 3620818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell "Did you forget to pass an event to " + 3630818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell "ScaleGestureDetector#onTouchEvent?"); 3640818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell index0 = findNewActiveIndex(event, 3650818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell mActiveId0 == mActiveId1 ? -1 : mActiveId1, index0); 3660818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell mActiveId0 = event.getPointerId(index0); 3670818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell } 3680818020d7cb04d83d51b71b8262d34bd79a76a95Adam Powell 369ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 370380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 371e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mGestureInProgress = mListener.onScaleBegin(this); 372e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 373e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell break; 374380b525220955ce4e4df8943b89082c7443ebfddAdam Powell 375e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell case MotionEvent.ACTION_POINTER_UP: { 376e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int pointerCount = event.getPointerCount(); 377e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int actionIndex = event.getActionIndex(); 378e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int actionId = event.getPointerId(actionIndex); 379e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 380e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell boolean gestureEnded = false; 381e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (pointerCount > 2) { 382e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (actionId == mActiveId0) { 383e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex); 384e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (newIndex >= 0) { 3850fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell mListener.onScaleEnd(this); 386e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId0 = event.getPointerId(newIndex); 3870fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell mActive0MostRecent = true; 3880fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell mPrevEvent = MotionEvent.obtain(event); 3890fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell setContext(event); 3900fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell mGestureInProgress = mListener.onScaleBegin(this); 391e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } else { 392e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell gestureEnded = true; 393e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 394e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } else if (actionId == mActiveId1) { 395e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex); 396e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (newIndex >= 0) { 3970fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell mListener.onScaleEnd(this); 398e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId1 = event.getPointerId(newIndex); 3990fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell mActive0MostRecent = false; 4000fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell mPrevEvent = MotionEvent.obtain(event); 4010fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell setContext(event); 4020fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell mGestureInProgress = mListener.onScaleBegin(this); 403e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } else { 404e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell gestureEnded = true; 405e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 406e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 407e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mPrevEvent.recycle(); 408e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mPrevEvent = MotionEvent.obtain(event); 409e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell setContext(event); 410e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } else { 411e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell gestureEnded = true; 412380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 413ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 414e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (gestureEnded) { 415e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // Gesture ended 416e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell setContext(event); 417e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 418e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // Set focus point to the remaining finger 419e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0; 420e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int index = event.findPointerIndex(activeId); 421e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusX = event.getX(index); 422e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mFocusY = event.getY(index); 423ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 424380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mListener.onScaleEnd(this); 425e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell reset(); 426e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId0 = activeId; 427e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActive0MostRecent = true; 428380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 429e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 430e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell break; 431ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 432e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell case MotionEvent.ACTION_CANCEL: 433e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mListener.onScaleEnd(this); 434ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell reset(); 435ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell break; 436ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 437e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell case MotionEvent.ACTION_UP: 438e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell reset(); 439e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell break; 440e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 441e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell case MotionEvent.ACTION_MOVE: { 442ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell setContext(event); 443ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 444ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // Only accept the event if our relative pressure is within 445ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // a certain limit - this can help filter shaky data as a 446ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell // finger is lifted. 447ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) { 448ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final boolean updatePrevious = mListener.onScale(this); 449ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 450ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (updatePrevious) { 451ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent.recycle(); 452ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = MotionEvent.obtain(event); 453ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 454ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 455e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 456e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell break; 457ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 458ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 459ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return handled; 460ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 46147c41e807e36999e4d0d2072e41a82bc45655ff2Erik 462e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell private int findNewActiveIndex(MotionEvent ev, int otherActiveId, int oldIndex) { 463e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int pointerCount = ev.getPointerCount(); 464e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 465e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // It's ok if this isn't found and returns -1, it simply won't match. 466e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int otherActiveIndex = ev.findPointerIndex(otherActiveId); 467e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell int newActiveIndex = -1; 468e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 469e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell // Pick a new id and update tracking state. Only pick pointers not on the slop edges. 470e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell for (int i = 0; i < pointerCount; i++) { 471e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (i != oldIndex && i != otherActiveIndex) { 472e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float edgeSlop = mEdgeSlop; 473e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float rightSlop = mRightSlopEdge; 474e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float bottomSlop = mBottomSlopEdge; 475e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float x = getRawX(ev, i); 476e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell float y = getRawY(ev, i); 477e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (x >= edgeSlop && y >= edgeSlop && x <= rightSlop && y <= bottomSlop) { 478e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell newActiveIndex = i; 479e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell break; 480e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 481e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 482e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 483e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 484e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell return newActiveIndex; 485e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell } 486e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 487380b525220955ce4e4df8943b89082c7443ebfddAdam Powell /** 48847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * MotionEvent has no getRawX(int) method; simulate it pending future API approval. 489380b525220955ce4e4df8943b89082c7443ebfddAdam Powell */ 490380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private static float getRawX(MotionEvent event, int pointerIndex) { 4910fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell if (pointerIndex < 0) return Float.MIN_VALUE; 492e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (pointerIndex == 0) return event.getRawX(); 4939bccdb7d5c93e350337e707bc6edf3cd017b8f96Adam Powell float offset = event.getRawX() - event.getX(); 494380b525220955ce4e4df8943b89082c7443ebfddAdam Powell return event.getX(pointerIndex) + offset; 495380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 49647c41e807e36999e4d0d2072e41a82bc45655ff2Erik 497380b525220955ce4e4df8943b89082c7443ebfddAdam Powell /** 49847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * MotionEvent has no getRawY(int) method; simulate it pending future API approval. 499380b525220955ce4e4df8943b89082c7443ebfddAdam Powell */ 500380b525220955ce4e4df8943b89082c7443ebfddAdam Powell private static float getRawY(MotionEvent event, int pointerIndex) { 5010fe4a135b78e3ee993dd5111cc3e48a5b48952fbAdam Powell if (pointerIndex < 0) return Float.MIN_VALUE; 502e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell if (pointerIndex == 0) return event.getRawY(); 5039bccdb7d5c93e350337e707bc6edf3cd017b8f96Adam Powell float offset = event.getRawY() - event.getY(); 504380b525220955ce4e4df8943b89082c7443ebfddAdam Powell return event.getY(pointerIndex) + offset; 505380b525220955ce4e4df8943b89082c7443ebfddAdam Powell } 506ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 507ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private void setContext(MotionEvent curr) { 508ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrEvent != null) { 509ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent.recycle(); 510ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 511ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent = MotionEvent.obtain(curr); 512ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 513ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrLen = -1; 514ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevLen = -1; 515ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mScaleFactor = -1; 516ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 517ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final MotionEvent prev = mPrevEvent; 518ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 519e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int prevIndex0 = prev.findPointerIndex(mActiveId0); 520e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int prevIndex1 = prev.findPointerIndex(mActiveId1); 521e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int currIndex0 = curr.findPointerIndex(mActiveId0); 522e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final int currIndex1 = curr.findPointerIndex(mActiveId1); 523e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell 524d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell if (prevIndex0 < 0 || prevIndex1 < 0 || currIndex0 < 0 || currIndex1 < 0) { 525d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell mInvalidGesture = true; 526d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell Log.e(TAG, "Invalid MotionEvent stream detected.", new Throwable()); 527d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell if (mGestureInProgress) { 528d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell mListener.onScaleEnd(this); 529d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell } 530d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell return; 531d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell } 532d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell 533e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float px0 = prev.getX(prevIndex0); 534e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float py0 = prev.getY(prevIndex0); 535e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float px1 = prev.getX(prevIndex1); 536e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float py1 = prev.getY(prevIndex1); 537e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float cx0 = curr.getX(currIndex0); 538e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float cy0 = curr.getY(currIndex0); 539e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float cx1 = curr.getX(currIndex1); 540e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell final float cy1 = curr.getY(currIndex1); 541ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 542ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvx = px1 - px0; 543ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvy = py1 - py0; 544ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvx = cx1 - cx0; 545ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvy = cy1 - cy0; 546ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevFingerDiffX = pvx; 547ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevFingerDiffY = pvy; 548ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrFingerDiffX = cvx; 549ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrFingerDiffY = cvy; 550ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 551ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusX = cx0 + cvx * 0.5f; 552ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mFocusY = cy0 + cvy * 0.5f; 553ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mTimeDelta = curr.getEventTime() - prev.getEventTime(); 554e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mCurrPressure = curr.getPressure(currIndex0) + curr.getPressure(currIndex1); 555e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mPrevPressure = prev.getPressure(prevIndex0) + prev.getPressure(prevIndex1); 556ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 557ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 558ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell private void reset() { 559ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mPrevEvent != null) { 560ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent.recycle(); 561ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mPrevEvent = null; 562ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 563ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrEvent != null) { 564ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent.recycle(); 565ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mCurrEvent = null; 566ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 567380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mSloppyGesture = false; 568380b525220955ce4e4df8943b89082c7443ebfddAdam Powell mGestureInProgress = false; 569e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId0 = -1; 570e33cef8037cb87386e17bcf8701a47452d262fa6Adam Powell mActiveId1 = -1; 571d0197f3669efda060c7ee2069ff41bd970fd6d9cAdam Powell mInvalidGesture = false; 572ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 573ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 574ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 575ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Returns {@code true} if a two-finger scale gesture is in progress. 576ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return {@code true} if a scale gesture is in progress, {@code false} otherwise. 577ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 578ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public boolean isInProgress() { 579ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mGestureInProgress; 580ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 581ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 582ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 583ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Get the X coordinate of the current gesture's focal point. 584ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is in progress, the focal point is directly between 585ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * the two pointers forming the gesture. 586ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is ending, the focal point is the location of the 587ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * remaining pointer on the screen. 588ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * If {@link #isInProgress()} would return false, the result of this 589ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * function is undefined. 59047c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 591ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return X coordinate of the focal point in pixels. 592ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 593ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getFocusX() { 594ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mFocusX; 595ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 596ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 597ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 598ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Get the Y coordinate of the current gesture's focal point. 599ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is in progress, the focal point is directly between 600ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * the two pointers forming the gesture. 601ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * If a gesture is ending, the focal point is the location of the 602ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * remaining pointer on the screen. 603ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * If {@link #isInProgress()} would return false, the result of this 604ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * function is undefined. 60547c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 606ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Y coordinate of the focal point in pixels. 607ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 608ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getFocusY() { 609ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mFocusY; 610ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 611ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 612ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 613ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the current distance between the two pointers forming the 614ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * gesture in progress. 61547c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 616ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Distance between pointers in pixels. 617ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 618ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getCurrentSpan() { 619ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mCurrLen == -1) { 620ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvx = mCurrFingerDiffX; 621ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float cvy = mCurrFingerDiffY; 622346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell mCurrLen = FloatMath.sqrt(cvx*cvx + cvy*cvy); 623ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 624ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mCurrLen; 625ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 626ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 627ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 62847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * Return the current x distance between the two pointers forming the 62947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * gesture in progress. 63047c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 63147c41e807e36999e4d0d2072e41a82bc45655ff2Erik * @return Distance between pointers in pixels. 63247c41e807e36999e4d0d2072e41a82bc45655ff2Erik */ 63347c41e807e36999e4d0d2072e41a82bc45655ff2Erik public float getCurrentSpanX() { 63447c41e807e36999e4d0d2072e41a82bc45655ff2Erik return mCurrFingerDiffX; 63547c41e807e36999e4d0d2072e41a82bc45655ff2Erik } 63647c41e807e36999e4d0d2072e41a82bc45655ff2Erik 63747c41e807e36999e4d0d2072e41a82bc45655ff2Erik /** 63847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * Return the current y distance between the two pointers forming the 63947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * gesture in progress. 64047c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 64147c41e807e36999e4d0d2072e41a82bc45655ff2Erik * @return Distance between pointers in pixels. 64247c41e807e36999e4d0d2072e41a82bc45655ff2Erik */ 64347c41e807e36999e4d0d2072e41a82bc45655ff2Erik public float getCurrentSpanY() { 64447c41e807e36999e4d0d2072e41a82bc45655ff2Erik return mCurrFingerDiffY; 64547c41e807e36999e4d0d2072e41a82bc45655ff2Erik } 64647c41e807e36999e4d0d2072e41a82bc45655ff2Erik 64747c41e807e36999e4d0d2072e41a82bc45655ff2Erik /** 648ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the previous distance between the two pointers forming the 649ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * gesture in progress. 65047c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 651ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Previous distance between pointers in pixels. 652ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 653ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getPreviousSpan() { 654ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mPrevLen == -1) { 655ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvx = mPrevFingerDiffX; 656ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell final float pvy = mPrevFingerDiffY; 657346c8fb036b99a33756c66dcebeb5d0f67a1df72Adam Powell mPrevLen = FloatMath.sqrt(pvx*pvx + pvy*pvy); 658ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 659ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mPrevLen; 660ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 661ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell 662ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 66347c41e807e36999e4d0d2072e41a82bc45655ff2Erik * Return the previous x distance between the two pointers forming the 66447c41e807e36999e4d0d2072e41a82bc45655ff2Erik * gesture in progress. 66547c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 66647c41e807e36999e4d0d2072e41a82bc45655ff2Erik * @return Previous distance between pointers in pixels. 66747c41e807e36999e4d0d2072e41a82bc45655ff2Erik */ 66847c41e807e36999e4d0d2072e41a82bc45655ff2Erik public float getPreviousSpanX() { 66947c41e807e36999e4d0d2072e41a82bc45655ff2Erik return mPrevFingerDiffX; 67047c41e807e36999e4d0d2072e41a82bc45655ff2Erik } 67147c41e807e36999e4d0d2072e41a82bc45655ff2Erik 67247c41e807e36999e4d0d2072e41a82bc45655ff2Erik /** 67347c41e807e36999e4d0d2072e41a82bc45655ff2Erik * Return the previous y distance between the two pointers forming the 67447c41e807e36999e4d0d2072e41a82bc45655ff2Erik * gesture in progress. 67547c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 67647c41e807e36999e4d0d2072e41a82bc45655ff2Erik * @return Previous distance between pointers in pixels. 67747c41e807e36999e4d0d2072e41a82bc45655ff2Erik */ 67847c41e807e36999e4d0d2072e41a82bc45655ff2Erik public float getPreviousSpanY() { 67947c41e807e36999e4d0d2072e41a82bc45655ff2Erik return mPrevFingerDiffY; 68047c41e807e36999e4d0d2072e41a82bc45655ff2Erik } 68147c41e807e36999e4d0d2072e41a82bc45655ff2Erik 68247c41e807e36999e4d0d2072e41a82bc45655ff2Erik /** 683ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the scaling factor from the previous scale event to the current 684ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * event. This value is defined as 685ab905c87b7324d15715b78eaae7ef8558ad3bd10Adam Powell * ({@link #getCurrentSpan()} / {@link #getPreviousSpan()}). 68647c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 687ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return The current scaling factor. 688ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 689ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public float getScaleFactor() { 690ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell if (mScaleFactor == -1) { 691ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell mScaleFactor = getCurrentSpan() / getPreviousSpan(); 692ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 693ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mScaleFactor; 694ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 69547c41e807e36999e4d0d2072e41a82bc45655ff2Erik 696ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 697ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the time difference in milliseconds between the previous 698ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * accepted scaling event and the current scaling event. 69947c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 700ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Time difference since the last scaling event in milliseconds. 701ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 702ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public long getTimeDelta() { 703ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mTimeDelta; 704ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 70547c41e807e36999e4d0d2072e41a82bc45655ff2Erik 706ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell /** 707ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * Return the event time of the current event being processed. 70847c41e807e36999e4d0d2072e41a82bc45655ff2Erik * 709ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell * @return Current event time in milliseconds. 710ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell */ 711ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell public long getEventTime() { 712ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell return mCurrEvent.getEventTime(); 713ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell } 714ae542ff055301a4c3c8a18e8da1739df3a771958Adam Powell} 715