1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <fstream>
17 #include <random>
18
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21
22 #define private public
23 #define protected public
24
25 #include "core/components_ng/event/touch_event.h"
26 #include "core/components_v2/inspector/inspector_constants.h"
27 #include "core/pipeline_ng/pipeline_context.h"
28 #include "frameworks/core/components_ng/pattern/root/root_pattern.h"
29 #include "core/pipeline/base/constants.h"
30
31 using namespace testing;
32 using namespace testing::ext;
33 using OHOS::Ace::TimeStamp;
34
35 namespace OHOS::Ace {
CalculateParabola(double a,double b,double c,double t,double angle)36 PointerEvent CalculateParabola(double a, double b, double c, double t, double angle)
37 {
38 double d = a * t * t + b * t + c;
39 PointerEvent p;
40 p.x = d * std::cos(angle);
41 p.y = d * std::sin(angle);
42 return p;
43 }
44
Get1stOrderDiff(const std::vector<TouchEvent> & events)45 std::vector<TouchEvent> Get1stOrderDiff(const std::vector<TouchEvent>& events)
46 {
47 std::vector<TouchEvent> diff;
48 for (int32_t i = 1; i < events.size(); ++i) {
49 TouchEvent p;
50 p.x = events[i].x - events[i - 1].x;
51 p.y = events[i].y - events[i - 1].y;
52 diff.push_back(p);
53 }
54 return diff;
55 }
56
Get2ndOrderDiff(const std::vector<TouchEvent> & events)57 std::vector<TouchEvent> Get2ndOrderDiff(const std::vector<TouchEvent>& events)
58 {
59 std::vector<TouchEvent> diff = Get1stOrderDiff(events);
60 return Get1stOrderDiff(diff);
61 }
62
GetStdDev(const std::vector<TouchEvent> & diff)63 double GetStdDev(const std::vector<TouchEvent>& diff)
64 {
65 double xAccumulate = 0;
66 double yAccumulate = 0;
67 for (auto& item : diff) {
68 xAccumulate += item.x;
69 yAccumulate += item.y;
70 }
71 double xMean = xAccumulate / diff.size();
72 double yMean = yAccumulate / diff.size();
73
74 xAccumulate = 0;
75 yAccumulate = 0;
76 for (auto& item : diff) {
77 xAccumulate += std::pow(item.x - xMean, 2);
78 yAccumulate += std::pow(item.y - yMean, 2);
79 }
80 return std::sqrt((xAccumulate + yAccumulate) / diff.size());
81 }
82
83 // using Parabola
SmoothBy2ndOrderDiff(const std::vector<TouchEvent> & events)84 double SmoothBy2ndOrderDiff(const std::vector<TouchEvent>& events)
85 {
86 auto diff = Get2ndOrderDiff(events);
87 return GetStdDev(diff);
88 }
89
90 // using linear
Monotonicity(const std::vector<TouchEvent> & events)91 double Monotonicity(const std::vector<TouchEvent>& events)
92 {
93 auto diff = Get1stOrderDiff(events);
94 if (diff.empty()) {
95 return 0.0;
96 }
97 PointerEvent& sign = diff[0];
98 for (auto& item : diff) {
99 if (item.x * sign.x < 0 || item.y * sign.y < 0) {
100 ADD_FAILURE();
101 }
102 }
103 return 0.0;
104 }
105
GetDeltaT(TimeStamp time,TimeStamp base)106 int64_t GetDeltaT(TimeStamp time, TimeStamp base)
107 {
108 auto deltaT = time - base;
109 return std::chrono::duration_cast<std::chrono::milliseconds>(deltaT).count();
110 }
111
GenerateCSV(const std::string & fileName,TimeStamp baseTime,const std::vector<TouchEvent> & tp,const std::vector<TouchEvent> & common,const std::vector<TouchEvent> & accelarate)112 void GenerateCSV(const std::string& fileName, TimeStamp baseTime, const std::vector<TouchEvent>& tp,
113 const std::vector<TouchEvent>& common, const std::vector<TouchEvent>& accelarate)
114 {
115 std::ofstream file(fileName);
116 if (!file.is_open()) {
117 std::cerr << "Cannot open the file: " << fileName << std::endl;
118 return;
119 }
120
121 // write head
122 file << "TpTime,TpDisplacement,"
123 << "CommonTime,CommonDisplacement,"
124 << "AccelarateTime,AccelarateDisplacement\n";
125 size_t maxSize = std::max({ tp.size(), common.size(), accelarate.size() });
126
127 // write data
128 for (size_t i = 0; i < maxSize; ++i) {
129 if (i < tp.size()) {
130 double d = std::sqrt(tp[i].x * tp[i].x + tp[i].y * tp[i].y);
131 file << GetDeltaT(tp[i].time, baseTime) << "," << d;
132 } else {
133 file << ",";
134 }
135
136 if (i < common.size()) {
137 double d = std::sqrt(common[i].x * common[i].x + common[i].y * common[i].y);
138 file << "," << GetDeltaT(common[i].time, baseTime) << "," << d;
139 } else {
140 file << ",,";
141 }
142
143 if (i < accelarate.size()) {
144 double d = std::sqrt(accelarate[i].x * accelarate[i].x + accelarate[i].y * accelarate[i].y);
145 file << "," << GetDeltaT(accelarate[i].time, baseTime) << "," << d << "\n";
146 } else {
147 file << ",,\n";
148 }
149 }
150 file.close();
151 }
152
153 struct TestResult {
154 double stddevOfAcc; // evaluate smooth
155 double stddevAgainstPhy; // evaluate accuracy
156 double stddevOfUniformSpeed; // evalueate stability
157 };
158
159 class MockEventManager : public EventManager {
160 DECLARE_ACE_TYPE(MockEventManager, OHOS::Ace::EventManager);
161
162 public:
163 MockEventManager() = default;
164 ~MockEventManager() override = default;
165
166 MOCK_METHOD(bool, DispatchTouchEvent, (const TouchEvent&, bool));
167 };
168
169 using NiceEventManager = NiceMock<MockEventManager>;
170
171 namespace NG {
172 using Generator = std::function<PointerEvent(double)>;
173 class ResampleTestNg : public testing::Test {
174 public:
175 static void SetUpTestSuite();
176 static void TearDownTestSuite();
177
178 static bool TestOnTouchEvent(const TouchEvent& event, bool sendOnTouch);
179 static vector<TouchEvent> events_;
180 static vector<TouchEvent> oriEvents_;
181 static RefPtr<PipelineContext> pipeline_;
182
183 void SetUp() override;
184 void TearDown() override;
185
186 /* simulate functions */
187 void SetGenerator(Generator&& f);
188 void GenerateTouchEvents(uint32_t duration);
189 void RunVsync(int32_t vsyncPeriodMs);
190 PointerEvent GetPhysicPoint(TimeStamp time);
191 TouchEvent GetOriginPoint(TimeStamp time);
192
193 /* test functions */
194 double GetCoordsDiffAgainstPhy();
195 void TestFastFlick(int32_t vsyncPeriod, TestResult& result);
196 void TestDeceleratingSlide(int32_t vsyncPeriod, TestResult& result);
197 void TestConstantSpeedSlide(int32_t vsyncPeriod, TestResult& result);
198 void TestSlowConstantSpeedSlide(int32_t vsyncPeriod, TestResult& result);
199
200 static constexpr uint32_t TP_RATE = 140;
201 static constexpr double NOISE_STD_DEV = 0.7;
202 static constexpr float NEAR_ZERO_DEV = 0.001;
203
204 TimeStamp nowTime_;
205 Generator func_;
206 };
207
208 std::vector<TouchEvent> ResampleTestNg::events_;
209 std::vector<TouchEvent> ResampleTestNg::oriEvents_;
210 RefPtr<PipelineContext> ResampleTestNg::pipeline_;
211
SetUpTestSuite()212 void ResampleTestNg::SetUpTestSuite()
213 {
214 pipeline_ = AceType::MakeRefPtr<PipelineContext>();
215 pipeline_->touchAccelarate_ = true;
216 pipeline_->rootNode_ = FrameNode::CreateFrameNodeWithTree(
217 V2::ROOT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<RootPattern>());
218 auto mockEventManager = AceType::MakeRefPtr<NiceEventManager>();
219 pipeline_->eventManager_ = mockEventManager;
220 ON_CALL((*mockEventManager), DispatchTouchEvent(testing::_, testing::_))
221 .WillByDefault(testing::Invoke(
222 [](const TouchEvent& event, bool sendOnTouch) { return TestOnTouchEvent(event, sendOnTouch); }));
223 }
224
TearDownTestSuite()225 void ResampleTestNg::TearDownTestSuite()
226 {
227 pipeline_ = nullptr;
228 }
229
SetUp()230 void ResampleTestNg::SetUp()
231 {
232 nowTime_ = std::chrono::high_resolution_clock::now();
233 }
234
TearDown()235 void ResampleTestNg::TearDown()
236 {
237 events_.clear();
238 oriEvents_.clear();
239 pipeline_->touchEvents_.clear();
240 func_ = nullptr;
241 }
242
GetPhysicPoint(TimeStamp time)243 PointerEvent ResampleTestNg::GetPhysicPoint(TimeStamp time)
244 {
245 auto deltaT = time - nowTime_;
246 int64_t t = std::chrono::duration_cast<std::chrono::milliseconds>(deltaT).count();
247 return func_(t);
248 }
249
GetOriginPoint(TimeStamp time)250 TouchEvent ResampleTestNg::GetOriginPoint(TimeStamp time)
251 {
252 auto deltaT = time - nowTime_;
253 int64_t t = std::chrono::duration_cast<std::chrono::milliseconds>(deltaT).count();
254 return oriEvents_[t * TP_RATE / 1000];
255 }
256
SetGenerator(Generator && f)257 void ResampleTestNg::SetGenerator(Generator&& f)
258 {
259 func_ = std::move(f);
260 }
261
262 // Generate a touch sequence with specific duration
GenerateTouchEvents(uint32_t duration)263 void ResampleTestNg::GenerateTouchEvents(uint32_t duration)
264 {
265 std::vector<TouchEvent> events;
266 uint32_t samplingRate = TP_RATE;
267 std::chrono::microseconds dt(1000000 / samplingRate);
268 std::chrono::microseconds deltaT(0);
269 std::chrono::milliseconds durationMs(duration);
270 std::random_device rd;
271 std::mt19937 gen(rd());
272 std::normal_distribution<double> noise(0.0, NOISE_STD_DEV);
273
274 // touch down
275 TouchEvent event;
276 event.SetId(0.0).SetX(0.0).SetY(0.0).SetType(TouchType::DOWN).SetTime(nowTime_);
277 oriEvents_.clear();
278 oriEvents_.emplace_back(event);
279
280 event.SetType(TouchType::MOVE);
281 do {
282 deltaT += dt;
283 double t = deltaT.count() / 1000;
284 PointerEvent p = func_(t);
285 event.SetX(p.x);
286 event.SetY(p.y);
287 event.SetTime(deltaT + nowTime_);
288 oriEvents_.emplace_back(event);
289 } while (deltaT <= durationMs);
290 }
291
RunVsync(int32_t vsyncHz)292 void ResampleTestNg::RunVsync(int32_t vsyncHz)
293 {
294 std::chrono::microseconds vsyncPeriod(1000000 / vsyncHz);
295 constexpr int64_t delay = 2000000; // simulate the 2ms delay between vsync and sensor time of event
296 int32_t i = 0;
297 auto vsyncTime = nowTime_;
298 int32_t cnt = 0;
299 events_.clear();
300 pipeline_->touchEvents_.clear();
301 while (i < oriEvents_.size()) {
302 while (i < oriEvents_.size() && oriEvents_[i].time < vsyncTime) {
303 pipeline_->touchEvents_.emplace_back(oriEvents_[i]);
304 i++;
305 }
306 int64_t vsynTimeNs = vsyncTime.time_since_epoch().count();
307 pipeline_->SetVsyncTime(vsynTimeNs + delay);
308 pipeline_->FlushTouchEvents();
309 pipeline_->resampleTimeStamp_ = vsynTimeNs + delay + 1000000; // instead of mock FlushVsync
310 vsyncTime += vsyncPeriod;
311 ++cnt;
312 }
313 }
314
TestOnTouchEvent(const TouchEvent & event,bool sendOnTouch)315 bool ResampleTestNg::TestOnTouchEvent(const TouchEvent& event, bool sendOnTouch)
316 {
317 events_.emplace_back(event);
318 return true;
319 }
320
GetCoordsDiffAgainstPhy()321 double ResampleTestNg::GetCoordsDiffAgainstPhy()
322 {
323 double variance = 0;
324 for (int32_t i = 0; i < events_.size(); ++i) {
325 auto base = GetPhysicPoint(events_[i].time);
326 double dx = events_[i].x - base.x;
327 double dy = events_[i].y - base.y;
328 variance += dx * dx + dy * dy;
329 }
330 return variance / events_.size();
331 }
332
TestFastFlick(int32_t vsyncPeriod,TestResult & result)333 void ResampleTestNg::TestFastFlick(int32_t vsyncPeriod, TestResult& result)
334 {
335 constexpr int32_t repeatTimes = 1;
336 double accumulateVar = 0;
337 double accumulateSmooth = 0;
338 SetGenerator([](double t) { return CalculateParabola(-0.0005, 0.8, 0, t, ACE_PI / 3); });
339 for (int32_t i = 0; i < repeatTimes; ++i) {
340 GenerateTouchEvents(500);
341 RunVsync(vsyncPeriod);
342 accumulateVar += GetCoordsDiffAgainstPhy();
343 accumulateSmooth += SmoothBy2ndOrderDiff(events_);
344 }
345 result.stddevAgainstPhy = std::sqrt(accumulateVar / repeatTimes);
346 result.stddevOfAcc = accumulateSmooth / repeatTimes;
347 }
348
349 /**
350 * @tc.name: ResampleTestFastFlick
351 * @tc.desc: Construct touch events and test resample sequence.
352 * @tc.type: FUNC
353 */
354 HWTEST_F(ResampleTestNg, ResampleTestFastFlick, TestSize.Level1)
355 {
356 TestResult result { 0 };
357 pipeline_->touchAccelarate_ = true;
358 TestFastFlick(60, result);
359 EXPECT_LT(result.stddevAgainstPhy, 0.157);
360 EXPECT_LT(result.stddevOfAcc, 0.537);
361 TestFastFlick(140, result);
362 EXPECT_LT(result.stddevAgainstPhy, 0.322);
363 EXPECT_LT(result.stddevOfAcc, 3.956);
364
365 pipeline_->touchAccelarate_ = false;
366 TestFastFlick(60, result);
367 EXPECT_LT(result.stddevAgainstPhy, 0.212);
368 EXPECT_LT(result.stddevOfAcc, 1.634);
369 TestFastFlick(140, result);
370 EXPECT_LT(result.stddevAgainstPhy, NEAR_ZERO_DEV);
371 EXPECT_LT(result.stddevOfAcc, 0.288);
372 }
373
TestDeceleratingSlide(int32_t vsyncPeriod,TestResult & result)374 void ResampleTestNg::TestDeceleratingSlide(int32_t vsyncPeriod, TestResult& result)
375 {
376 constexpr int32_t repeatTimes = 1;
377 double accumulateVar = 0;
378 double accumulateSmooth = 0;
379 SetGenerator([](double t) { return CalculateParabola(-0.0001, 0.3, 0, t, ACE_PI / 6); });
380 for (int32_t i = 0; i < repeatTimes; ++i) {
381 GenerateTouchEvents(500);
382 RunVsync(60);
383 accumulateVar += GetCoordsDiffAgainstPhy();
384 accumulateSmooth += SmoothBy2ndOrderDiff(events_);
385 }
386 result.stddevAgainstPhy = std::sqrt(accumulateVar / repeatTimes);
387 result.stddevOfAcc = accumulateSmooth / repeatTimes;
388 }
389
390 /**
391 * @tc.name: ResampleTestDeceleratingSlide
392 * @tc.desc: Construct touch events and test resample sequence.
393 * @tc.type: FUNC
394 */
395 HWTEST_F(ResampleTestNg, ResampleTestDeceleratingSlide, TestSize.Level1)
396 {
397 TestResult result { 0 };
398 pipeline_->touchAccelarate_ = true;
399 TestDeceleratingSlide(60, result);
400 EXPECT_LT(result.stddevAgainstPhy, 0.075);
401 EXPECT_LT(result.stddevOfAcc, 0.357);
402 TestDeceleratingSlide(140, result);
403 EXPECT_LT(result.stddevAgainstPhy, 0.075);
404 EXPECT_LT(result.stddevOfAcc, 0.357);
405
406 pipeline_->touchAccelarate_ = false;
407 TestDeceleratingSlide(60, result);
408 EXPECT_LT(result.stddevAgainstPhy, 0.098);
409 EXPECT_LT(result.stddevOfAcc, 0.625);
410 TestDeceleratingSlide(140, result);
411 EXPECT_LT(result.stddevAgainstPhy, 0.098);
412 EXPECT_LT(result.stddevOfAcc, 0.625);
413 }
414
TestConstantSpeedSlide(int32_t vsyncPeriod,TestResult & result)415 void ResampleTestNg::TestConstantSpeedSlide(int32_t vsyncPeriod, TestResult& result)
416 {
417 constexpr int32_t repeatTimes = 1;
418 double accumulateVar = 0;
419 double accumulateSmooth = 0;
420 pipeline_->touchAccelarate_ = false;
421 SetGenerator([](double t) { return CalculateParabola(0, 0.2, 0, t, 0); });
422 for (int32_t i = 0; i < repeatTimes; ++i) {
423 GenerateTouchEvents(1000);
424 RunVsync(60);
425 accumulateVar += GetCoordsDiffAgainstPhy();
426 accumulateSmooth += Monotonicity(events_);
427 }
428 result.stddevAgainstPhy = std::sqrt(accumulateVar / repeatTimes);
429 result.stddevOfUniformSpeed = accumulateSmooth / repeatTimes;
430 }
431
432 /**
433 * @tc.name: ResampleTestConstantSpeedSlide
434 * @tc.desc: Construct touch events and test resample sequence.
435 * @tc.type: FUNC
436 */
437 HWTEST_F(ResampleTestNg, ResampleTestConstantSpeedSlide, TestSize.Level1)
438 {
439 TestResult result { 0 };
440 pipeline_->touchAccelarate_ = true;
441 TestConstantSpeedSlide(60, result);
442 EXPECT_LT(result.stddevAgainstPhy, NEAR_ZERO_DEV);
443 EXPECT_LT(result.stddevOfUniformSpeed, 0.656);
444 TestConstantSpeedSlide(140, result);
445 EXPECT_LT(result.stddevAgainstPhy, NEAR_ZERO_DEV);
446 EXPECT_LT(result.stddevOfUniformSpeed, 0.656);
447
448 pipeline_->touchAccelarate_ = false;
449 TestConstantSpeedSlide(60, result);
450 EXPECT_LT(result.stddevAgainstPhy, NEAR_ZERO_DEV);
451 EXPECT_LT(result.stddevOfUniformSpeed, 0.656);
452 TestConstantSpeedSlide(140, result);
453 EXPECT_LT(result.stddevAgainstPhy, NEAR_ZERO_DEV);
454 EXPECT_LT(result.stddevOfUniformSpeed, 0.656);
455 }
456
TestSlowConstantSpeedSlide(int32_t vsyncPeriod,TestResult & result)457 void ResampleTestNg::TestSlowConstantSpeedSlide(int32_t vsyncPeriod, TestResult& result)
458 {
459 constexpr int32_t repeatTimes = 1;
460 double accumulateVar = 0;
461 double accumulateSmooth = 0;
462 SetGenerator([](double t) { return CalculateParabola(0, 0.05, 0, t, 0); });
463 for (int32_t i = 0; i < repeatTimes; ++i) {
464 GenerateTouchEvents(1000);
465 RunVsync(60);
466 accumulateVar += GetCoordsDiffAgainstPhy();
467 accumulateSmooth += Monotonicity(events_);
468 }
469 result.stddevAgainstPhy = std::sqrt(accumulateVar / repeatTimes);
470 result.stddevOfUniformSpeed = accumulateSmooth / repeatTimes;
471 }
472
473 /**
474 * @tc.name: ResampleTestSlowConstantSpeedSlide
475 * @tc.desc: Construct touch events and test resample sequence.
476 * @tc.type: FUNC
477 */
478 HWTEST_F(ResampleTestNg, ResampleTestSlowConstantSpeedSlide, TestSize.Level1)
479 {
480 TestResult result { 0 };
481 pipeline_->touchAccelarate_ = true;
482 TestSlowConstantSpeedSlide(60, result);
483 EXPECT_LT(result.stddevAgainstPhy, 0.013);
484 EXPECT_LT(result.stddevOfUniformSpeed, 0.086);
485 TestSlowConstantSpeedSlide(140, result);
486 EXPECT_LT(result.stddevAgainstPhy, 0.013);
487 EXPECT_LT(result.stddevOfUniformSpeed, 0.086);
488
489 pipeline_->touchAccelarate_ = false;
490 TestSlowConstantSpeedSlide(60, result);
491 EXPECT_LT(result.stddevAgainstPhy, NEAR_ZERO_DEV);
492 EXPECT_LT(result.stddevOfUniformSpeed, 0.164);
493 TestSlowConstantSpeedSlide(140, result);
494 EXPECT_LT(result.stddevAgainstPhy, NEAR_ZERO_DEV);
495 EXPECT_LT(result.stddevOfUniformSpeed, 0.164);
496 }
497
498 HWTEST_F(ResampleTestNg, ResampleTestRealData01, TestSize.Level1)
499 {
500 pipeline_->touchAccelarate_ = true;
501 std::vector<TouchEvent> events;
502
503 TouchEvent event;
504 int64_t sinceEpoch = 343641809000; // real trace data
505 std::chrono::microseconds us_since_epoch(sinceEpoch);
506 TimeStamp stamp(us_since_epoch);
507 nowTime_ = stamp;
508 event.SetId(0.0).SetX(0.0).SetY(0.0).SetType(TouchType::DOWN).SetTime(stamp);
509 oriEvents_.clear();
510 oriEvents_.emplace_back(event);
511
512 event.SetType(TouchType::MOVE);
513 // real trace data
514 std::vector<std::vector<int64_t>> logPoints { { 343641816000, 1735, 300 }, { 343641823000, 1736, 300 },
515 { 343641830000, 1738, 300 }, { 343641837000, 1739, 300 }, { 343641844000, 1740, 300 },
516 { 343641851000, 1742, 300 }, { 343641858000, 1743, 300 }, { 343641865000, 1745, 300 },
517 { 343641872000, 1746, 300 }, { 343641879000, 1747, 300 }, { 343641886000, 1749, 300 },
518 { 343641893000, 1750, 300 }, { 343641900000, 1752, 300 }, { 343641907000, 1753, 300 },
519 { 343641914000, 1754, 300 }, { 343641921000, 1756, 300 }, { 343641928000, 1757, 300 },
520 { 343641935000, 1759, 300 }, { 343641942000, 1760, 300 }, { 343641949000, 1761, 300 },
521 { 343641958000, 1763, 300 }, { 343641963000, 1764, 300 } };
522 for (const auto& item : logPoints) {
523 std::chrono::microseconds msEpoch(item[0]);
524 TimeStamp t(msEpoch);
525 event.SetX(item[1]).SetY(item[2]).SetTime(t);
526 oriEvents_.emplace_back(event);
527 }
528 events_.clear();
529 pipeline_->touchEvents_.clear();
530
531 // real trace data
532 std::vector<int64_t> vsyncTime { 343641803424377, 343641820086409, 343641836748819, 343641853410582,
533 343641870072479, 343641886735032, 343641903397442, 343641920059816, 343641936722405, 343641953686073,
534 343641970348577, 343641987010997, 343642003671915 };
535 int32_t vsyncIdx = 0;
536 int32_t i = 0;
537 while (i < oriEvents_.size()) {
538 std::chrono::nanoseconds nsEpoch(vsyncTime[vsyncIdx]);
539 TimeStamp t(nsEpoch);
540 while (i < oriEvents_.size() && oriEvents_[i].time < t) {
541 pipeline_->touchEvents_.emplace_back(oriEvents_[i]);
542 i++;
543 }
544 pipeline_->SetVsyncTime(vsyncTime[vsyncIdx]);
545 pipeline_->FlushTouchEvents();
546 ++vsyncIdx;
547 }
548 Monotonicity(events_);
549 }
550 } // namespace NG
551 } // namespace OHOS::Ace