Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a gesture failure problem on iOS #6145

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 67 additions & 10 deletions shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@
#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h"
#include "flutter/shell/platform/darwin/ios/platform_view_ios.h"

static double kTouchTrackerCheckInterval = 1.f;

@interface FlutterViewController () <FlutterTextInputDelegate>
@property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
@property(nonatomic, retain) NSMutableSet* touchTrackerSet;
@property(nonatomic, retain) NSMutableDictionary<NSValue*, NSNumber*>* touchTrackerDict;

@end

@interface FlutterViewControllerRegistrar : NSObject <FlutterPluginRegistrar>
Expand Down Expand Up @@ -70,6 +75,9 @@ - (instancetype)initWithProject:(FlutterDartProject*)projectOrNil
else
_dartProject.reset([projectOrNil retain]);

_touchTrackerSet = [[NSMutableSet set] retain];
_touchTrackerDict = [[NSMutableDictionary dictionary] retain];

[self performCommonViewControllerInitialization];
}

Expand Down Expand Up @@ -476,6 +484,9 @@ - (void)viewDidDisappear:(BOOL)animated {
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_pluginPublications release];
[_touchTrackerSet release];
[_touchTrackerDict release];

[super dealloc];
}

Expand Down Expand Up @@ -547,30 +558,51 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase(UITouc
return blink::PointerData::DeviceKind::kTouch;
}

- (void)dispatchTouches:(NSSet*)touches phase:(UITouchPhase)phase {
- (void)dispatchTouches:(NSSet*)touches phase:(UITouchPhase)phase trackTouches:(BOOL)bTrack {
// Note: we cannot rely on touch.phase, since in some cases, e.g.,
// handleStatusBarTouches, we synthesize touches from existing events.
//
// TODO(cbracken) consider creating out own class with the touch fields we
// need.
NSTimeInterval tsNow = [[NSDate date] timeIntervalSinceReferenceDate];
auto eventTypePhase = PointerChangePhaseFromUITouchPhase(phase);
const CGFloat scale = [UIScreen mainScreen].scale;
auto packet = std::make_unique<blink::PointerDataPacket>(touches.count);

int i = 0;
for (UITouch* touch in touches) {
int device_id = 0;
NSValue* key = [NSValue valueWithPointer:(void*)touch];

switch (eventTypePhase.second) {
case Accessed:
case Accessed: {
device_id = _touchMapper.identifierOf(touch);
if (bTrack) {
[self.touchTrackerSet addObject:touch];
self.touchTrackerDict[key] = @(tsNow + kTouchTrackerCheckInterval);
}
break;
case Added:
}
case Added: {
device_id = _touchMapper.registerTouch(touch);
if (bTrack) {
[self.touchTrackerSet addObject:touch];
self.touchTrackerDict[key] = @(tsNow + kTouchTrackerCheckInterval);
}
break;
case Removed:
}
case Removed: {
device_id = _touchMapper.unregisterTouch(touch);
if (bTrack) {
[self.touchTrackerDict removeObjectForKey:key];
[self.touchTrackerSet removeObject:touch];
}
break;
}
}

if (device_id == 0) {
continue;
}

FML_DCHECK(device_id != 0);
Expand Down Expand Up @@ -656,19 +688,44 @@ - (void)dispatchTouches:(NSSet*)touches phase:(UITouchPhase)phase {
}

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
[self dispatchTouches:touches phase:UITouchPhaseBegan];
[self dispatchTouches:touches phase:UITouchPhaseBegan trackTouches:TRUE];
[self checkIfCompleteTouches];
}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
[self dispatchTouches:touches phase:UITouchPhaseMoved];
[self dispatchTouches:touches phase:UITouchPhaseMoved trackTouches:TRUE];
}

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
[self dispatchTouches:touches phase:UITouchPhaseEnded];
[self dispatchTouches:touches phase:UITouchPhaseEnded trackTouches:TRUE];
}

- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
[self dispatchTouches:touches phase:UITouchPhaseCancelled];
[self dispatchTouches:touches phase:UITouchPhaseCancelled trackTouches:TRUE];
}

- (BOOL)checkIfCompleteTouches {
NSInteger cnt = self.touchTrackerSet.count;
if (cnt <= 0)
return FALSE;
NSTimeInterval tsNow = [[NSDate date] timeIntervalSinceReferenceDate];
NSSet* tmpTrackingTouches = [self.touchTrackerSet copy];
NSMutableSet* set = [NSMutableSet set];
for (UITouch* touch in tmpTrackingTouches) {
NSValue* key = [NSValue valueWithPointer:(void*)touch];
NSNumber* expiredTime = [self.touchTrackerDict objectForKey:key];
if (expiredTime.doubleValue <= tsNow) {
[set addObject:touch];
[self.touchTrackerDict removeObjectForKey:key];
[self.touchTrackerSet removeObject:touch];
}
}
if (set.count > 0) {
[self dispatchTouches:set phase:UITouchPhaseBegan trackTouches:FALSE];
[self dispatchTouches:set phase:UITouchPhaseCancelled trackTouches:FALSE];
return TRUE;
}
return FALSE;
}

#pragma mark - Handle view resizing
Expand Down Expand Up @@ -973,8 +1030,8 @@ - (void)handleStatusBarTouches:(UIEvent*)event {
CGPoint screenLoc = [touch.window convertPoint:windowLoc toWindow:nil];
if (CGRectContainsPoint(statusBarFrame, screenLoc)) {
NSSet* statusbarTouches = [NSSet setWithObject:touch];
[self dispatchTouches:statusbarTouches phase:UITouchPhaseBegan];
[self dispatchTouches:statusbarTouches phase:UITouchPhaseEnded];
[self dispatchTouches:statusbarTouches phase:UITouchPhaseBegan trackTouches:TRUE];
[self dispatchTouches:statusbarTouches phase:UITouchPhaseEnded trackTouches:TRUE];
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,29 @@
TouchMapper::~TouchMapper() = default;

int TouchMapper::registerTouch(UITouch* touch) {
if (touch_map_.find(touch) != touch_map_.end()) {
return 0;
}
int freeSpot = ffsll(free_spots_);
touch_map_[touch] = freeSpot;
free_spots_ &= ~(1 << (freeSpot - 1));
return freeSpot;
}

int TouchMapper::unregisterTouch(UITouch* touch) {
if (touch_map_.find(touch) == touch_map_.end()) {
return 0;
}
auto index = touch_map_[touch];
free_spots_ |= 1 << (index - 1);
touch_map_.erase(touch);
return index;
}

int TouchMapper::identifierOf(UITouch* touch) const {
if (touch_map_.find(touch) == touch_map_.end()) {
return 0;
}
return touch_map_.at(touch);
}

Expand Down