liyuqian 9675ca2f6b
Reland "Smooth out iOS irregular input events delivery (#12280)" (#12385)
This reverts commit c2879cae2ee3707ad07af1118bf4862dc1d82bb7.

Additionally, we fix https://github.com/flutter/flutter/issues/40863 by adding a secondary VSYNC callback.

Unit tests are updated to provide VSYNC mocking and check the fix of https://github.com/flutter/flutter/issues/40863.

The root cause of having https://github.com/flutter/flutter/issues/40863 is the false assumption that each input event must trigger a new frame. That was true in the framework PR https://github.com/flutter/flutter/pull/36616 because the input events there are all scrolling move events. When the PR was ported to the engine, we can no longer distinguish different types of events, and tap events may no longer trigger a new frame.

Therefore, this PR directly hooks into the `VsyncWaiter` and uses its (newly added) secondary callback to dispatch the pending input event.
2019-09-30 11:25:50 -07:00

113 lines
3.1 KiB
Dart

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert' show utf8, json;
import 'dart:isolate';
import 'dart:typed_data';
import 'dart:ui';
void main() {}
void nativeReportTimingsCallback(List<int> timings) native 'NativeReportTimingsCallback';
void nativeOnBeginFrame(int microseconds) native 'NativeOnBeginFrame';
void nativeOnPointerDataPacket() native 'NativeOnPointerDataPacket';
@pragma('vm:entry-point')
void reportTimingsMain() {
window.onReportTimings = (List<FrameTiming> timings) {
List<int> timestamps = [];
for (FrameTiming t in timings) {
for (FramePhase phase in FramePhase.values) {
timestamps.add(t.timestampInMicroseconds(phase));
}
}
nativeReportTimingsCallback(timestamps);
};
}
@pragma('vm:entry-point')
void onBeginFrameMain() {
window.onBeginFrame = (Duration beginTime) {
nativeOnBeginFrame(beginTime.inMicroseconds);
};
}
@pragma('vm:entry-point')
void onPointerDataPacketMain() {
window.onPointerDataPacket = (PointerDataPacket packet) {
nativeOnPointerDataPacket();
};
}
@pragma('vm:entry-point')
void emptyMain() {}
@pragma('vm:entry-point')
void dummyReportTimingsMain() {
window.onReportTimings = (List<FrameTiming> timings) {};
}
@pragma('vm:entry-point')
void fixturesAreFunctionalMain() {
sayHiFromFixturesAreFunctionalMain();
}
void sayHiFromFixturesAreFunctionalMain() native 'SayHiFromFixturesAreFunctionalMain';
void notifyNative() native 'NotifyNative';
void secondaryIsolateMain(String message) {
print('Secondary isolate got message: ' + message);
notifyNative();
}
@pragma('vm:entry-point')
void testCanLaunchSecondaryIsolate() {
Isolate.spawn(secondaryIsolateMain, 'Hello from root isolate.');
notifyNative();
}
@pragma('vm:entry-point')
void testSkiaResourceCacheSendsResponse() {
final PlatformMessageResponseCallback callback = (ByteData data) {
if (data == null) {
throw 'Response must not be null.';
}
final String response = utf8.decode(data.buffer.asUint8List());
final List<bool> jsonResponse = json.decode(response).cast<bool>();
if (jsonResponse[0] != true) {
throw 'Response was not true';
}
notifyNative();
};
const String jsonRequest = '''{
"method": "Skia.setResourceCacheMaxBytes",
"args": 10000
}''';
window.sendPlatformMessage(
'flutter/skia',
Uint8List.fromList(utf8.encode(jsonRequest)).buffer.asByteData(),
callback,
);
}
void notifyWidthHeight(int width, int height) native 'NotifyWidthHeight';
@pragma('vm:entry-point')
void canCreateImageFromDecompressedData() {
const int imageWidth = 10;
const int imageHeight = 10;
final Uint8List pixels = Uint8List.fromList(List<int>.generate(
imageWidth * imageHeight * 4,
(int i) => i % 4 < 2 ? 0x00 : 0xFF,
));
decodeImageFromPixels(
pixels, imageWidth, imageHeight, PixelFormat.rgba8888,
(Image image) {
notifyWidthHeight(image.width, image.height);
});
}