Make sure FlutterViewController flushs all pending touches when no longer active (flutter/engine#8400)
This commit is contained in:
@@ -39,6 +39,7 @@ NSNotificationName const FlutterSemanticsUpdateNotification = @"FlutterSemantics
|
||||
BOOL _initialized;
|
||||
BOOL _viewOpaque;
|
||||
BOOL _engineNeedsLaunch;
|
||||
NSMutableSet<NSNumber*>* _ongoingTouches;
|
||||
}
|
||||
|
||||
#pragma mark - Manage and override all designated initializers
|
||||
@@ -54,6 +55,7 @@ NSNotificationName const FlutterSemanticsUpdateNotification = @"FlutterSemantics
|
||||
_engineNeedsLaunch = NO;
|
||||
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
|
||||
_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(self);
|
||||
_ongoingTouches = [[NSMutableSet alloc] init];
|
||||
|
||||
[self performCommonViewControllerInitialization];
|
||||
[engine setViewController:self];
|
||||
@@ -75,6 +77,7 @@ NSNotificationName const FlutterSemanticsUpdateNotification = @"FlutterSemantics
|
||||
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
|
||||
[_engine.get() createShell:nil libraryURI:nil];
|
||||
_engineNeedsLaunch = YES;
|
||||
_ongoingTouches = [[NSMutableSet alloc] init];
|
||||
[self loadDefaultSplashScreenView];
|
||||
[self performCommonViewControllerInitialization];
|
||||
}
|
||||
@@ -427,9 +430,44 @@ NSNotificationName const FlutterSemanticsUpdateNotification = @"FlutterSemantics
|
||||
TRACE_EVENT0("flutter", "viewDidDisappear");
|
||||
[self surfaceUpdated:NO];
|
||||
[[_engine.get() lifecycleChannel] sendMessage:@"AppLifecycleState.paused"];
|
||||
[self flushOngoingTouches];
|
||||
|
||||
[super viewDidDisappear:animated];
|
||||
}
|
||||
|
||||
- (void)flushOngoingTouches {
|
||||
if (_ongoingTouches.count > 0) {
|
||||
auto packet = std::make_unique<blink::PointerDataPacket>(_ongoingTouches.count);
|
||||
size_t pointer_index = 0;
|
||||
// If the view controller is going away, we want to flush cancel all the ongoing
|
||||
// touches to the framework so nothing gets orphaned.
|
||||
for (NSNumber* device in _ongoingTouches) {
|
||||
// Create fake PointerData to balance out each previously started one for the framework.
|
||||
blink::PointerData pointer_data;
|
||||
pointer_data.Clear();
|
||||
|
||||
constexpr int kMicrosecondsPerSecond = 1000 * 1000;
|
||||
// Use current time.
|
||||
pointer_data.time_stamp = [[NSDate date] timeIntervalSince1970] * kMicrosecondsPerSecond;
|
||||
|
||||
pointer_data.change = blink::PointerData::Change::kCancel;
|
||||
pointer_data.kind = blink::PointerData::DeviceKind::kTouch;
|
||||
pointer_data.device = device.longLongValue;
|
||||
|
||||
// Anything we put here will be arbitrary since there are no touches.
|
||||
pointer_data.physical_x = 0;
|
||||
pointer_data.physical_y = 0;
|
||||
pointer_data.pressure = 1.0;
|
||||
pointer_data.pressure_max = 1.0;
|
||||
|
||||
packet->SetPointerData(pointer_index++, pointer_data);
|
||||
}
|
||||
|
||||
[_ongoingTouches removeAllObjects];
|
||||
[_engine.get() dispatchPointerDataPacket:std::move(packet)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_engine.get() notifyViewControllerDeallocated];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
@@ -528,6 +566,27 @@ static blink::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch) {
|
||||
pointer_data.physical_x = windowCoordinates.x * scale;
|
||||
pointer_data.physical_y = windowCoordinates.y * scale;
|
||||
|
||||
NSNumber* deviceKey = [NSNumber numberWithLongLong:pointer_data.device];
|
||||
// Track touches that began and not yet stopped so we can flush them
|
||||
// if the view controller goes away.
|
||||
switch (pointer_data.change) {
|
||||
case blink::PointerData::Change::kDown:
|
||||
[_ongoingTouches addObject:deviceKey];
|
||||
break;
|
||||
case blink::PointerData::Change::kCancel:
|
||||
case blink::PointerData::Change::kUp:
|
||||
[_ongoingTouches removeObject:deviceKey];
|
||||
break;
|
||||
case blink::PointerData::Change::kHover:
|
||||
case blink::PointerData::Change::kMove:
|
||||
// We're only tracking starts and stops.
|
||||
break;
|
||||
case blink::PointerData::Change::kAdd:
|
||||
case blink::PointerData::Change::kRemove:
|
||||
// We don't use kAdd/kRemove.
|
||||
break;
|
||||
}
|
||||
|
||||
// pressure_min is always 0.0
|
||||
if (@available(iOS 9, *)) {
|
||||
// These properties were introduced in iOS 9.0.
|
||||
|
||||
Reference in New Issue
Block a user