Skip to content

Commit

Permalink
Fix timestamp of touch events should use system startup time (#30422)
Browse files Browse the repository at this point in the history
  • Loading branch information
wangying3426 committed Mar 13, 2022
1 parent bbebccd commit 56187fa
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 10 deletions.
23 changes: 13 additions & 10 deletions shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
Expand Up @@ -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<flutter::PointerDataPacket>(/*count=*/1);
pointer_data.change = change;
packet->SetPointerData(0, pointer_data);
Expand Down Expand Up @@ -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;

Expand Down
Expand Up @@ -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"
Expand Down Expand Up @@ -138,6 +139,7 @@ - (void)startKeyBoardAnimation:(NSTimeInterval)duration;
- (void)ensureViewportMetricsIsCorrect;
- (void)invalidateDisplayLink;
- (void)addInternalPlugins;
- (flutter::PointerData)generatePointerDataForFake;
@end

@interface FlutterViewControllerTest : XCTestCase
Expand Down Expand Up @@ -1092,4 +1094,17 @@ - (void)testMouseSupport API_AVAILABLE(ios(13.4)) {
dispatchPointerDataPacket:std::make_unique<flutter::PointerDataPacket>(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

0 comments on commit 56187fa

Please sign in to comment.