1919import android .content .Context ;
2020import android .os .SystemClock ;
2121import android .util .FloatMath ;
22- import android .util .Log ;
23-
24- import java .util .Arrays ;
2522
2623/**
2724 * Detects scaling transformation gestures using the supplied {@link MotionEvent}s.
@@ -143,11 +140,16 @@ public void onScaleEnd(ScaleGestureDetector detector) {
143140 private int mSpanSlop ;
144141 private int mMinSpan ;
145142
146- private float [] mTouchHistoryLastAccepted ;
147- private int [] mTouchHistoryDirection ;
148- private long [] mTouchHistoryLastAcceptedTime ;
143+ // Bounds for recently seen values
144+ private float mTouchUpper ;
145+ private float mTouchLower ;
146+ private float mTouchHistoryLastAccepted ;
147+ private int mTouchHistoryDirection ;
148+ private long mTouchHistoryLastAcceptedTime ;
149+ private int mTouchMinMajor ;
149150
150151 private static final long TOUCH_STABILIZE_TIME = 128 ; // ms
152+ private static final int TOUCH_MIN_MAJOR = 48 ; // dp
151153
152154 /**
153155 * Consistency verifier for debugging purposes.
@@ -160,6 +162,8 @@ public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
160162 mContext = context ;
161163 mListener = listener ;
162164 mSpanSlop = ViewConfiguration .get (context ).getScaledTouchSlop () * 2 ;
165+ mTouchMinMajor =
166+ (int ) (context .getResources ().getDisplayMetrics ().density * TOUCH_MIN_MAJOR + 0.5f );
163167 mMinSpan = context .getResources ().getDimensionPixelSize (
164168 com .android .internal .R .dimen .config_minScalingSpan );
165169 }
@@ -172,123 +176,67 @@ public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
172176 private void addTouchHistory (MotionEvent ev ) {
173177 final long currentTime = SystemClock .uptimeMillis ();
174178 final int count = ev .getPointerCount ();
179+ boolean accept = currentTime - mTouchHistoryLastAcceptedTime >= TOUCH_STABILIZE_TIME ;
180+ float total = 0 ;
181+ int sampleCount = 0 ;
175182 for (int i = 0 ; i < count ; i ++) {
176- final int id = ev .getPointerId (i );
177- ensureTouchHistorySize (id );
178-
179- final boolean hasLastAccepted = !Float .isNaN (mTouchHistoryLastAccepted [id ]);
180- boolean accept = true ;
183+ final boolean hasLastAccepted = !Float .isNaN (mTouchHistoryLastAccepted );
181184 final int historySize = ev .getHistorySize ();
182- for ( int h = 0 ; h < historySize + 1 ; h ++) {
183- final float major ;
184- final float minor ;
185+ final int pointerSampleCount = historySize + 1 ;
186+ for ( int h = 0 ; h < pointerSampleCount ; h ++) {
187+ float major ;
185188 if (h < historySize ) {
186189 major = ev .getHistoricalTouchMajor (i , h );
187- minor = ev .getHistoricalTouchMinor (i , h );
188190 } else {
189191 major = ev .getTouchMajor (i );
190- minor = ev .getTouchMinor (i );
191192 }
192- final float avg = (major + minor ) / 2 ;
193+ if (major < mTouchMinMajor ) major = mTouchMinMajor ;
194+ total += major ;
195+
196+ if (Float .isNaN (mTouchUpper ) || major > mTouchUpper ) {
197+ mTouchUpper = major ;
198+ }
199+ if (Float .isNaN (mTouchLower ) || major < mTouchLower ) {
200+ mTouchLower = major ;
201+ }
193202
194203 if (hasLastAccepted ) {
195- final int directionSig = (int ) Math .signum (avg - mTouchHistoryLastAccepted [ id ] );
196- if (directionSig != mTouchHistoryDirection [ id ] ||
197- (directionSig == 0 && mTouchHistoryDirection [ id ] == 0 )) {
198- mTouchHistoryDirection [ id ] = directionSig ;
204+ final int directionSig = (int ) Math .signum (major - mTouchHistoryLastAccepted );
205+ if (directionSig != mTouchHistoryDirection ||
206+ (directionSig == 0 && mTouchHistoryDirection == 0 )) {
207+ mTouchHistoryDirection = directionSig ;
199208 final long time = h < historySize ? ev .getHistoricalEventTime (h )
200209 : ev .getEventTime ();
201- mTouchHistoryLastAcceptedTime [id ] = time ;
202- accept = false ;
203- }
204- if (currentTime - mTouchHistoryLastAcceptedTime [id ] < TOUCH_STABILIZE_TIME ) {
210+ mTouchHistoryLastAcceptedTime = time ;
205211 accept = false ;
206212 }
207213 }
208214 }
209-
210- if (accept ) {
211- float newAccepted = (ev .getTouchMajor (i ) + ev .getTouchMinor (i )) / 2 ;
212- if (hasLastAccepted ) {
213- newAccepted = (mTouchHistoryLastAccepted [id ] + newAccepted ) / 2 ;
214- }
215- mTouchHistoryLastAccepted [id ] = newAccepted ;
216- mTouchHistoryDirection [id ] = 0 ;
217- mTouchHistoryLastAcceptedTime [id ] = ev .getEventTime ();
218- }
215+ sampleCount += pointerSampleCount ;
219216 }
220- }
221217
222- /**
223- * Clear out the touch history for a given pointer id.
224- * @param id pointer id to clear
225- * @see #addTouchHistory(MotionEvent)
226- */
227- private boolean removeTouchHistoryForId (int id ) {
228- if (id >= mTouchHistoryLastAccepted .length ) {
229- return false ;
230- }
231- mTouchHistoryLastAccepted [id ] = Float .NaN ;
232- mTouchHistoryDirection [id ] = 0 ;
233- mTouchHistoryLastAcceptedTime [id ] = 0 ;
234- return true ;
235- }
218+ final float avg = total / sampleCount ;
236219
237- /**
238- * Get the adjusted combined touchMajor/touchMinor value for a given pointer id
239- * @param id the pointer id of the data to obtain
240- * @return the adjusted major/minor value for the point at id
241- * @see #addTouchHistory(MotionEvent)
242- */
243- private float getAdjustedTouchHistory (int id ) {
244- if (id >= mTouchHistoryLastAccepted .length ) {
245- Log .e (TAG , "Error retrieving adjusted touch history for id=" + id +
246- " - incomplete event stream?" );
247- return 0 ;
220+ if (accept ) {
221+ float newAccepted = (mTouchUpper + mTouchLower + avg ) / 3 ;
222+ mTouchUpper = (mTouchUpper + newAccepted ) / 2 ;
223+ mTouchLower = (mTouchLower + newAccepted ) / 2 ;
224+ mTouchHistoryLastAccepted = newAccepted ;
225+ mTouchHistoryDirection = 0 ;
226+ mTouchHistoryLastAcceptedTime = ev .getEventTime ();
248227 }
249- return mTouchHistoryLastAccepted [id ];
250228 }
251229
252230 /**
253231 * Clear all touch history tracking. Useful in ACTION_CANCEL or ACTION_UP.
254232 * @see #addTouchHistory(MotionEvent)
255233 */
256234 private void clearTouchHistory () {
257- if (mTouchHistoryLastAccepted == null ) {
258- // All three arrays will be null if this is the case; nothing to do.
259- return ;
260- }
261- Arrays .fill (mTouchHistoryLastAccepted , Float .NaN );
262- Arrays .fill (mTouchHistoryDirection , 0 );
263- Arrays .fill (mTouchHistoryLastAcceptedTime , 0 );
264- }
265-
266- private void ensureTouchHistorySize (int id ) {
267- final int requiredSize = id + 1 ;
268- if (mTouchHistoryLastAccepted == null || mTouchHistoryLastAccepted .length < requiredSize ) {
269- final float [] newLastAccepted = new float [requiredSize ];
270- final int [] newDirection = new int [requiredSize ];
271- final long [] newLastAcceptedTime = new long [requiredSize ];
272-
273- int oldLength = 0 ;
274- if (mTouchHistoryLastAccepted != null ) {
275- System .arraycopy (mTouchHistoryLastAccepted , 0 , newLastAccepted , 0 ,
276- mTouchHistoryLastAccepted .length );
277- System .arraycopy (mTouchHistoryDirection , 0 , newDirection , 0 ,
278- mTouchHistoryDirection .length );
279- System .arraycopy (mTouchHistoryLastAcceptedTime , 0 , newLastAcceptedTime , 0 ,
280- mTouchHistoryLastAcceptedTime .length );
281- oldLength = mTouchHistoryLastAccepted .length ;
282- }
283-
284- Arrays .fill (newLastAccepted , oldLength , newLastAccepted .length , Float .NaN );
285- Arrays .fill (newDirection , oldLength , newDirection .length , 0 );
286- Arrays .fill (newLastAcceptedTime , oldLength , newLastAcceptedTime .length , 0 );
287-
288- mTouchHistoryLastAccepted = newLastAccepted ;
289- mTouchHistoryDirection = newDirection ;
290- mTouchHistoryLastAcceptedTime = newLastAcceptedTime ;
291- }
235+ mTouchUpper = Float .NaN ;
236+ mTouchLower = Float .NaN ;
237+ mTouchHistoryLastAccepted = Float .NaN ;
238+ mTouchHistoryDirection = 0 ;
239+ mTouchHistoryLastAcceptedTime = 0 ;
292240 }
293241
294242 /**
@@ -346,23 +294,16 @@ public boolean onTouchEvent(MotionEvent event) {
346294 final float focusX = sumX / div ;
347295 final float focusY = sumY / div ;
348296
349- if (pointerUp ) {
350- final int id = event .getPointerId (event .getActionIndex ());
351- if (!removeTouchHistoryForId (id )) {
352- Log .e (TAG , "Got ACTION_POINTER_UP for previously unknown id=" + id +
353- " - incomplete event stream?" );
354- }
355- } else {
356- addTouchHistory (event );
357- }
297+
298+ addTouchHistory (event );
358299
359300 // Determine average deviation from focal point
360301 float devSumX = 0 , devSumY = 0 ;
361302 for (int i = 0 ; i < count ; i ++) {
362303 if (skipIndex == i ) continue ;
363304
364- // Average touch major and touch minor and convert the resulting diameter into a radius.
365- final float touchSize = getAdjustedTouchHistory ( event . getPointerId ( i )) / 2 ;
305+ // Convert the resulting diameter into a radius.
306+ final float touchSize = mTouchHistoryLastAccepted / 2 ;
366307 devSumX += Math .abs (event .getX (i ) - focusX ) + touchSize ;
367308 devSumY += Math .abs (event .getY (i ) - focusY ) + touchSize ;
368309 }
0 commit comments