Skip to content

Commit 076f173

Browse files
author
Jeff Brown
committed
Remove edge slop handling from ScaleGestureDetector.
The edge slop code could violate invariants of ScaleGestureDetector, such as the assumption that if an ACTION_POINTER_DOWN is observed or if getPointerCount() >= 2, then there must be at least two active pointers to choose from. But due to the edge slop handling, it was possible for findNewActiveIndex to return -1 in this case, resulting in a crash. Bug: 6613154 Change-Id: I4e08e38a49ab27dac1be9484e19de086bc43624a
1 parent 5ebf04c commit 076f173

File tree

1 file changed

+29
-201
lines changed

1 file changed

+29
-201
lines changed

core/java/android/view/ScaleGestureDetector.java

Lines changed: 29 additions & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,6 @@ public void onScaleEnd(ScaleGestureDetector detector) {
152152
private float mPrevPressure;
153153
private long mTimeDelta;
154154

155-
private final float mEdgeSlop;
156-
private float mRightSlopEdge;
157-
private float mBottomSlopEdge;
158-
private boolean mSloppyGesture;
159155
private boolean mInvalidGesture;
160156

161157
// Pointer IDs currently responsible for the two fingers controlling the gesture
@@ -171,10 +167,8 @@ public void onScaleEnd(ScaleGestureDetector detector) {
171167
new InputEventConsistencyVerifier(this, 0) : null;
172168

173169
public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
174-
ViewConfiguration config = ViewConfiguration.get(context);
175170
mContext = context;
176171
mListener = listener;
177-
mEdgeSlop = config.getScaledEdgeSlop();
178172
}
179173

180174
public boolean onTouchEvent(MotionEvent event) {
@@ -193,171 +187,37 @@ public boolean onTouchEvent(MotionEvent event) {
193187
handled = false;
194188
} else if (!mGestureInProgress) {
195189
switch (action) {
196-
case MotionEvent.ACTION_DOWN: {
197-
mActiveId0 = event.getPointerId(0);
198-
mActive0MostRecent = true;
199-
}
200-
break;
201-
202-
case MotionEvent.ACTION_UP:
203-
reset();
190+
case MotionEvent.ACTION_DOWN: {
191+
mActiveId0 = event.getPointerId(0);
192+
mActive0MostRecent = true;
193+
}
204194
break;
205195

206-
case MotionEvent.ACTION_POINTER_DOWN: {
207-
// We have a new multi-finger gesture
208-
209-
// as orientation can change, query the metrics in touch down
210-
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
211-
mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
212-
mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
213-
214-
if (mPrevEvent != null) mPrevEvent.recycle();
215-
mPrevEvent = MotionEvent.obtain(event);
216-
mTimeDelta = 0;
217-
218-
int index1 = event.getActionIndex();
219-
int index0 = event.findPointerIndex(mActiveId0);
220-
mActiveId1 = event.getPointerId(index1);
221-
if (index0 < 0 || index0 == index1) {
222-
// Probably someone sending us a broken event stream.
223-
index0 = findNewActiveIndex(event, index0 == index1 ? -1 : mActiveId1, index0);
224-
mActiveId0 = event.getPointerId(index0);
225-
}
226-
mActive0MostRecent = false;
227-
228-
setContext(event);
229-
230-
// Check if we have a sloppy gesture. If so, delay
231-
// the beginning of the gesture until we're sure that's
232-
// what the user wanted. Sloppy gestures can happen if the
233-
// edge of the user's hand is touching the screen, for example.
234-
final float edgeSlop = mEdgeSlop;
235-
final float rightSlop = mRightSlopEdge;
236-
final float bottomSlop = mBottomSlopEdge;
237-
float x0 = getRawX(event, index0);
238-
float y0 = getRawY(event, index0);
239-
float x1 = getRawX(event, index1);
240-
float y1 = getRawY(event, index1);
241-
242-
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
243-
|| x0 > rightSlop || y0 > bottomSlop;
244-
boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
245-
|| x1 > rightSlop || y1 > bottomSlop;
246-
247-
if (p0sloppy && p1sloppy) {
248-
mFocusX = -1;
249-
mFocusY = -1;
250-
mSloppyGesture = true;
251-
} else if (p0sloppy) {
252-
mFocusX = event.getX(index1);
253-
mFocusY = event.getY(index1);
254-
mSloppyGesture = true;
255-
} else if (p1sloppy) {
256-
mFocusX = event.getX(index0);
257-
mFocusY = event.getY(index0);
258-
mSloppyGesture = true;
259-
} else {
260-
mSloppyGesture = false;
261-
mGestureInProgress = mListener.onScaleBegin(this);
262-
}
263-
}
264-
break;
265-
266-
case MotionEvent.ACTION_MOVE:
267-
if (mSloppyGesture) {
268-
// Initiate sloppy gestures if we've moved outside of the slop area.
269-
final float edgeSlop = mEdgeSlop;
270-
final float rightSlop = mRightSlopEdge;
271-
final float bottomSlop = mBottomSlopEdge;
272-
int index0 = event.findPointerIndex(mActiveId0);
273-
int index1 = event.findPointerIndex(mActiveId1);
274-
275-
float x0 = getRawX(event, index0);
276-
float y0 = getRawY(event, index0);
277-
float x1 = getRawX(event, index1);
278-
float y1 = getRawY(event, index1);
279-
280-
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
281-
|| x0 > rightSlop || y0 > bottomSlop;
282-
boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
283-
|| x1 > rightSlop || y1 > bottomSlop;
284-
285-
if (p0sloppy) {
286-
// Do we have a different pointer that isn't sloppy?
287-
int index = findNewActiveIndex(event, mActiveId1, index0);
288-
if (index >= 0) {
289-
index0 = index;
290-
mActiveId0 = event.getPointerId(index);
291-
x0 = getRawX(event, index);
292-
y0 = getRawY(event, index);
293-
p0sloppy = false;
294-
}
295-
}
196+
case MotionEvent.ACTION_UP:
197+
reset();
198+
break;
296199

297-
if (p1sloppy) {
298-
// Do we have a different pointer that isn't sloppy?
299-
int index = findNewActiveIndex(event, mActiveId0, index1);
300-
if (index >= 0) {
301-
index1 = index;
302-
mActiveId1 = event.getPointerId(index);
303-
x1 = getRawX(event, index);
304-
y1 = getRawY(event, index);
305-
p1sloppy = false;
306-
}
307-
}
200+
case MotionEvent.ACTION_POINTER_DOWN: {
201+
// We have a new multi-finger gesture
202+
if (mPrevEvent != null) mPrevEvent.recycle();
203+
mPrevEvent = MotionEvent.obtain(event);
204+
mTimeDelta = 0;
308205

309-
if(p0sloppy && p1sloppy) {
310-
mFocusX = -1;
311-
mFocusY = -1;
312-
} else if (p0sloppy) {
313-
mFocusX = event.getX(index1);
314-
mFocusY = event.getY(index1);
315-
} else if (p1sloppy) {
316-
mFocusX = event.getX(index0);
317-
mFocusY = event.getY(index0);
318-
} else {
319-
mSloppyGesture = false;
320-
mGestureInProgress = mListener.onScaleBegin(this);
206+
int index1 = event.getActionIndex();
207+
int index0 = event.findPointerIndex(mActiveId0);
208+
mActiveId1 = event.getPointerId(index1);
209+
if (index0 < 0 || index0 == index1) {
210+
// Probably someone sending us a broken event stream.
211+
index0 = findNewActiveIndex(event, mActiveId1, -1);
212+
mActiveId0 = event.getPointerId(index0);
321213
}
322-
}
323-
break;
324-
325-
case MotionEvent.ACTION_POINTER_UP:
326-
if (mSloppyGesture) {
327-
final int pointerCount = event.getPointerCount();
328-
final int actionIndex = event.getActionIndex();
329-
final int actionId = event.getPointerId(actionIndex);
330-
331-
if (pointerCount > 2) {
332-
if (actionId == mActiveId0) {
333-
final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex);
334-
if (newIndex >= 0) mActiveId0 = event.getPointerId(newIndex);
335-
} else if (actionId == mActiveId1) {
336-
final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex);
337-
if (newIndex >= 0) mActiveId1 = event.getPointerId(newIndex);
338-
}
339-
} else {
340-
// Set focus point to the remaining finger
341-
final int index = event.findPointerIndex(actionId == mActiveId0 ?
342-
mActiveId1 : mActiveId0);
343-
if (index < 0) {
344-
mInvalidGesture = true;
345-
Log.e(TAG, "Invalid MotionEvent stream detected.", new Throwable());
346-
if (mGestureInProgress) {
347-
mListener.onScaleEnd(this);
348-
}
349-
return false;
350-
}
214+
mActive0MostRecent = false;
351215

352-
mActiveId0 = event.getPointerId(index);
216+
setContext(event);
353217

354-
mActive0MostRecent = true;
355-
mActiveId1 = -1;
356-
mFocusX = event.getX(index);
357-
mFocusY = event.getY(index);
358-
}
218+
mGestureInProgress = mListener.onScaleBegin(this);
219+
break;
359220
}
360-
break;
361221
}
362222
} else {
363223
// Transform gesture in progress - attempt to handle it
@@ -381,8 +241,7 @@ public boolean onTouchEvent(MotionEvent event) {
381241
" with bad state while a gesture was in progress. " +
382242
"Did you forget to pass an event to " +
383243
"ScaleGestureDetector#onTouchEvent?");
384-
index0 = findNewActiveIndex(event,
385-
mActiveId0 == mActiveId1 ? -1 : mActiveId1, index0);
244+
index0 = findNewActiveIndex(event, mActiveId1, -1);
386245
mActiveId0 = event.getPointerId(index0);
387246
}
388247

@@ -483,49 +342,19 @@ public boolean onTouchEvent(MotionEvent event) {
483342
return handled;
484343
}
485344

486-
private int findNewActiveIndex(MotionEvent ev, int otherActiveId, int oldIndex) {
345+
private int findNewActiveIndex(MotionEvent ev, int otherActiveId, int removedPointerIndex) {
487346
final int pointerCount = ev.getPointerCount();
488347

489348
// It's ok if this isn't found and returns -1, it simply won't match.
490349
final int otherActiveIndex = ev.findPointerIndex(otherActiveId);
491-
int newActiveIndex = -1;
492350

493-
// Pick a new id and update tracking state. Only pick pointers not on the slop edges.
351+
// Pick a new id and update tracking state.
494352
for (int i = 0; i < pointerCount; i++) {
495-
if (i != oldIndex && i != otherActiveIndex) {
496-
final float edgeSlop = mEdgeSlop;
497-
final float rightSlop = mRightSlopEdge;
498-
final float bottomSlop = mBottomSlopEdge;
499-
float x = getRawX(ev, i);
500-
float y = getRawY(ev, i);
501-
if (x >= edgeSlop && y >= edgeSlop && x <= rightSlop && y <= bottomSlop) {
502-
newActiveIndex = i;
503-
break;
504-
}
353+
if (i != removedPointerIndex && i != otherActiveIndex) {
354+
return i;
505355
}
506356
}
507-
508-
return newActiveIndex;
509-
}
510-
511-
/**
512-
* MotionEvent has no getRawX(int) method; simulate it pending future API approval.
513-
*/
514-
private static float getRawX(MotionEvent event, int pointerIndex) {
515-
if (pointerIndex < 0) return Float.MIN_VALUE;
516-
if (pointerIndex == 0) return event.getRawX();
517-
float offset = event.getRawX() - event.getX();
518-
return event.getX(pointerIndex) + offset;
519-
}
520-
521-
/**
522-
* MotionEvent has no getRawY(int) method; simulate it pending future API approval.
523-
*/
524-
private static float getRawY(MotionEvent event, int pointerIndex) {
525-
if (pointerIndex < 0) return Float.MIN_VALUE;
526-
if (pointerIndex == 0) return event.getRawY();
527-
float offset = event.getRawY() - event.getY();
528-
return event.getY(pointerIndex) + offset;
357+
return -1;
529358
}
530359

531360
private void setContext(MotionEvent curr) {
@@ -588,7 +417,6 @@ private void reset() {
588417
mCurrEvent.recycle();
589418
mCurrEvent = null;
590419
}
591-
mSloppyGesture = false;
592420
mGestureInProgress = false;
593421
mActiveId0 = -1;
594422
mActiveId1 = -1;

0 commit comments

Comments
 (0)