iOS: Gracefully handle cancelling of subset of active touches

When applying the five-finger pinch gesture, we get a touchesCancelled
callback with all five touch points, but the pinch gesture ends when
the second to last finger is released from the screen. The last finger
will not emit any more touch events, _but_, will contribute to starting
another pinch gesture. That second pinch gesture will _not_ trigger a
touchesCancelled event when starting, but as each finger is released,
and we may get touchesMoved events for the remaining fingers.

The event property 'allTouches' contains one less touch point than it
should, so this behavior is likely a bug in the iOS system gesture
recognizer, but have to take it into account when maintaining the Qt
touch state.

We do this by assuming that there are no cases where a sub-set of the
active touch events are intentionally cancelled, and always clear the
list of active touches.

Task-number: QTBUG-37304
Change-Id: Icee79978508ecbc6854c0fb55d2da48b99d92f96
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
This commit is contained in:
Tor Arne Vestbø 2014-05-06 16:37:54 +02:00 committed by The Qt Project
parent d7e0c926b5
commit 36caeadb4d

View File

@ -292,19 +292,33 @@
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!touches && m_activeTouches.isEmpty())
if (m_activeTouches.isEmpty())
return;
if (!touches) {
m_activeTouches.clear();
} else {
for (UITouch *touch in touches)
m_activeTouches.remove(touch);
// When four-finger swiping, we get a touchesCancelled callback
// which includes all four touch points. The swipe gesture is
// then active until all four touches have been released, and
// we start getting touchesBegan events again.
Q_ASSERT_X(m_activeTouches.isEmpty(), Q_FUNC_INFO,
"Subset of active touches cancelled by UIKit");
}
// When five-finger pinching, we also get a touchesCancelled
// callback with all five touch points, but the pinch gesture
// ends when the second to last finger is released from the
// screen. The last finger will not emit any more touch
// events, _but_, will contribute to starting another pinch
// gesture. That second pinch gesture will _not_ trigger a
// touchesCancelled event when starting, but as each finger
// is released, and we may get touchesMoved events for the
// remaining fingers. [event allTouches] also contains one
// less touch point than it should, so this behavior is
// likely a bug in the iOS system gesture recognizer, but we
// have to take it into account when maintaining the Qt state.
// We do this by assuming that there are no cases where a
// sub-set of the active touch events are intentionally cancelled.
if (touches && (static_cast<NSInteger>([touches count]) != m_activeTouches.count()))
qWarning("Subset of active touches cancelled by UIKit");
m_activeTouches.clear();
m_nextTouchId = 0;
NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime];