diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index c53a8778d7995..b497d0917580a 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -421,16 +421,24 @@ - (void)loadView { _scrollView.reset(scrollView); } +- (flutter::PointerData)generatePointerDataForFake { + flutter::PointerData pointer_data; + pointer_data.Clear(); + pointer_data.kind = flutter::PointerData::DeviceKind::kTouch; + // `UITouch.timestamp` is defined as seconds since system startup. Synthesized events can get this + // time with `NSProcessInfo.systemUptime`. See + // https://developer.apple.com/documentation/uikit/uitouch/1618144-timestamp?language=objc + pointer_data.time_stamp = [[NSProcessInfo processInfo] systemUptime] * kMicrosecondsPerSecond; + return pointer_data; +} + static void SendFakeTouchEvent(FlutterEngine* engine, CGPoint location, flutter::PointerData::Change change) { const CGFloat scale = [UIScreen mainScreen].scale; - flutter::PointerData pointer_data; - pointer_data.Clear(); + flutter::PointerData pointer_data = [[engine viewController] generatePointerDataForFake]; pointer_data.physical_x = location.x * scale; pointer_data.physical_y = location.y * scale; - pointer_data.kind = flutter::PointerData::DeviceKind::kTouch; - pointer_data.time_stamp = [[NSDate date] timeIntervalSince1970] * kMicrosecondsPerSecond; auto packet = std::make_unique(/*count=*/1); pointer_data.change = change; packet->SetPointerData(0, pointer_data); @@ -759,14 +767,9 @@ - (void)flushOngoingTouches { // touches to the framework so nothing gets orphaned. for (NSNumber* device in _ongoingTouches.get()) { // Create fake PointerData to balance out each previously started one for the framework. - flutter::PointerData pointer_data; - pointer_data.Clear(); - - // Use current time. - pointer_data.time_stamp = [[NSDate date] timeIntervalSince1970] * kMicrosecondsPerSecond; + flutter::PointerData pointer_data = [self generatePointerDataForFake]; pointer_data.change = flutter::PointerData::Change::kCancel; - pointer_data.kind = flutter::PointerData::DeviceKind::kTouch; pointer_data.device = device.longLongValue; pointer_data.pointer_identifier = 0; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index d6f3e0f9a1f78..8d838d72d02ec 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -7,6 +7,7 @@ #include "flutter/fml/platform/darwin/message_loop_darwin.h" #import "flutter/lib/ui/window/platform_configuration.h" +#include "flutter/lib/ui/window/pointer_data.h" #import "flutter/lib/ui/window/viewport_metrics.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" @@ -138,6 +139,7 @@ - (void)startKeyBoardAnimation:(NSTimeInterval)duration; - (void)ensureViewportMetricsIsCorrect; - (void)invalidateDisplayLink; - (void)addInternalPlugins; +- (flutter::PointerData)generatePointerDataForFake; @end @interface FlutterViewControllerTest : XCTestCase @@ -1092,4 +1094,17 @@ - (void)testMouseSupport API_AVAILABLE(ios(13.4)) { dispatchPointerDataPacket:std::make_unique(0)]; } +- (void)testFakeEventTimeStamp { + FlutterViewController* vc = [[FlutterViewController alloc] initWithEngine:self.mockEngine + nibName:nil + bundle:nil]; + XCTAssertNotNil(vc); + + flutter::PointerData pointer_data = [vc generatePointerDataForFake]; + int64_t current_micros = [[NSProcessInfo processInfo] systemUptime] * 1000 * 1000; + int64_t interval_micros = current_micros - pointer_data.time_stamp; + const int64_t tolerance_millis = 2; + XCTAssertTrue(interval_micros / 1000 < tolerance_millis, + @"PointerData.time_stamp should be equal to NSProcessInfo.systemUptime"); +} @end