1c29fa5a6Sopenharmony_ci/*
2c29fa5a6Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3c29fa5a6Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4c29fa5a6Sopenharmony_ci * you may not use this file except in compliance with the License.
5c29fa5a6Sopenharmony_ci * You may obtain a copy of the License at
6c29fa5a6Sopenharmony_ci *
7c29fa5a6Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8c29fa5a6Sopenharmony_ci *
9c29fa5a6Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10c29fa5a6Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11c29fa5a6Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12c29fa5a6Sopenharmony_ci * See the License for the specific language governing permissions and
13c29fa5a6Sopenharmony_ci * limitations under the License.
14c29fa5a6Sopenharmony_ci */
15c29fa5a6Sopenharmony_ci
16c29fa5a6Sopenharmony_ci#include "event_resample.h"
17c29fa5a6Sopenharmony_ci
18c29fa5a6Sopenharmony_ci#include "event_log_helper.h"
19c29fa5a6Sopenharmony_ci#include "input_device_manager.h"
20c29fa5a6Sopenharmony_ci#include "i_input_windows_manager.h"
21c29fa5a6Sopenharmony_ci#include "mmi_log.h"
22c29fa5a6Sopenharmony_ci#include "util.h"
23c29fa5a6Sopenharmony_ci
24c29fa5a6Sopenharmony_ci#undef MMI_LOG_DOMAIN
25c29fa5a6Sopenharmony_ci#define MMI_LOG_DOMAIN MMI_LOG_SERVER
26c29fa5a6Sopenharmony_ci#undef MMI_LOG_TAG
27c29fa5a6Sopenharmony_ci#define MMI_LOG_TAG "EventResample"
28c29fa5a6Sopenharmony_ci
29c29fa5a6Sopenharmony_cinamespace OHOS {
30c29fa5a6Sopenharmony_cinamespace MMI {
31c29fa5a6Sopenharmony_ciEventResample::EventResample(){};
32c29fa5a6Sopenharmony_ciEventResample::~EventResample(){};
33c29fa5a6Sopenharmony_ci
34c29fa5a6Sopenharmony_cistd::shared_ptr<PointerEvent> EventResample::OnEventConsume(std::shared_ptr<PointerEvent> pointerEvent,
35c29fa5a6Sopenharmony_ci                                                            int64_t frameTime, ErrCode &status)
36c29fa5a6Sopenharmony_ci{
37c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
38c29fa5a6Sopenharmony_ci    MotionEvent* outEvent = nullptr;
39c29fa5a6Sopenharmony_ci    ErrCode result = ERR_OK;
40c29fa5a6Sopenharmony_ci
41c29fa5a6Sopenharmony_ci    status = ERR_OK;
42c29fa5a6Sopenharmony_ci    if (ERR_OK != InitializeInputEvent(pointerEvent, frameTime)) {
43c29fa5a6Sopenharmony_ci        status = ERR_WOULD_BLOCK;
44c29fa5a6Sopenharmony_ci        return pointerEvent;
45c29fa5a6Sopenharmony_ci    }
46c29fa5a6Sopenharmony_ci
47c29fa5a6Sopenharmony_ci    do {
48c29fa5a6Sopenharmony_ci        // All events are dispathed so consume batches
49c29fa5a6Sopenharmony_ci        if (PointerEvent::POINTER_ACTION_UNKNOWN == inputEvent_.pointerAction) {
50c29fa5a6Sopenharmony_ci            result = ConsumeBatch(frameTime_, &outEvent);
51c29fa5a6Sopenharmony_ci            frameTime_ = 0;
52c29fa5a6Sopenharmony_ci            if ((ERR_OK == result) && (nullptr != outEvent)) {
53c29fa5a6Sopenharmony_ci                status = result;
54c29fa5a6Sopenharmony_ci                break;
55c29fa5a6Sopenharmony_ci            } else {
56c29fa5a6Sopenharmony_ci                status = result;
57c29fa5a6Sopenharmony_ci                return nullptr;
58c29fa5a6Sopenharmony_ci            }
59c29fa5a6Sopenharmony_ci        }
60c29fa5a6Sopenharmony_ci
61c29fa5a6Sopenharmony_ci        // Add event into batch
62c29fa5a6Sopenharmony_ci        if (UpdateBatch(&outEvent, result)) {
63c29fa5a6Sopenharmony_ci            break;
64c29fa5a6Sopenharmony_ci        }
65c29fa5a6Sopenharmony_ci
66c29fa5a6Sopenharmony_ci        // Update touch state object
67c29fa5a6Sopenharmony_ci        EventDump("UpdateTouchState", inputEvent_);
68c29fa5a6Sopenharmony_ci        EventLogHelper::PrintEventData(pointerEvent_, MMI_LOG_HEADER);
69c29fa5a6Sopenharmony_ci        PrintfDeviceName();
70c29fa5a6Sopenharmony_ci        UpdateTouchState(inputEvent_);
71c29fa5a6Sopenharmony_ci        return pointerEvent_;
72c29fa5a6Sopenharmony_ci    } while (0);
73c29fa5a6Sopenharmony_ci
74c29fa5a6Sopenharmony_ci    if ((ERR_OK == result) && (nullptr != outEvent)) {
75c29fa5a6Sopenharmony_ci        // Update pointer event
76c29fa5a6Sopenharmony_ci        UpdatePointerEvent(outEvent);
77c29fa5a6Sopenharmony_ci        EventLogHelper::PrintEventData(pointerEvent_, MMI_LOG_HEADER);
78c29fa5a6Sopenharmony_ci        PrintfDeviceName();
79c29fa5a6Sopenharmony_ci        return pointerEvent_;
80c29fa5a6Sopenharmony_ci    }
81c29fa5a6Sopenharmony_ci
82c29fa5a6Sopenharmony_ci    return nullptr;
83c29fa5a6Sopenharmony_ci}
84c29fa5a6Sopenharmony_ci
85c29fa5a6Sopenharmony_cistd::shared_ptr<PointerEvent> EventResample::GetPointerEvent()
86c29fa5a6Sopenharmony_ci{
87c29fa5a6Sopenharmony_ci    return pointerEvent_;
88c29fa5a6Sopenharmony_ci}
89c29fa5a6Sopenharmony_ci
90c29fa5a6Sopenharmony_civoid EventResample::EventDump(const char *msg, MotionEvent &event)
91c29fa5a6Sopenharmony_ci{
92c29fa5a6Sopenharmony_ci    MMI_HILOGD("%{public}s: pointerAction:%{public}d, actionTime:%{public}" PRId64 ", pointerCount:%{public}d,"
93c29fa5a6Sopenharmony_ci               "sourceType:%{public}d, deviceId:%{public}d, eventId:%{public}d",
94c29fa5a6Sopenharmony_ci               msg, event.pointerAction, event.actionTime, event.pointerCount,
95c29fa5a6Sopenharmony_ci               event.sourceType, event.deviceId, event.eventId);
96c29fa5a6Sopenharmony_ci    for (auto &it : event.pointers) {
97c29fa5a6Sopenharmony_ci        MMI_HILOGD("ID:%{public}d, coordX:%d, coordY:%d, toolType:%{public}d",
98c29fa5a6Sopenharmony_ci            it.second.id, it.second.coordX, it.second.coordY, it.second.toolType);
99c29fa5a6Sopenharmony_ci    }
100c29fa5a6Sopenharmony_ci}
101c29fa5a6Sopenharmony_ci
102c29fa5a6Sopenharmony_ciErrCode EventResample::InitializeInputEvent(std::shared_ptr<PointerEvent> pointerEvent, int64_t frameTime)
103c29fa5a6Sopenharmony_ci{
104c29fa5a6Sopenharmony_ci    int32_t pointerAction = PointerEvent::POINTER_ACTION_UNKNOWN;
105c29fa5a6Sopenharmony_ci
106c29fa5a6Sopenharmony_ci    if (pointerEvent != nullptr) {
107c29fa5a6Sopenharmony_ci        pointerEvent_ = pointerEvent;
108c29fa5a6Sopenharmony_ci    }
109c29fa5a6Sopenharmony_ci
110c29fa5a6Sopenharmony_ci    if (frameTime_ <= 0) {
111c29fa5a6Sopenharmony_ci        if (0 != frameTime) {
112c29fa5a6Sopenharmony_ci            frameTime_ = frameTime;
113c29fa5a6Sopenharmony_ci        } else if (nullptr != pointerEvent) {
114c29fa5a6Sopenharmony_ci            frameTime_ = GetSysClockTime();
115c29fa5a6Sopenharmony_ci        } else {
116c29fa5a6Sopenharmony_ci            frameTime_ = 0;
117c29fa5a6Sopenharmony_ci        }
118c29fa5a6Sopenharmony_ci    }
119c29fa5a6Sopenharmony_ci
120c29fa5a6Sopenharmony_ci    // Check that event can be consumed and initialize motion event.
121c29fa5a6Sopenharmony_ci    if (nullptr != pointerEvent) {
122c29fa5a6Sopenharmony_ci        EventLogHelper::PrintEventData(pointerEvent_, MMI_LOG_HEADER);
123c29fa5a6Sopenharmony_ci        PrintfDeviceName();
124c29fa5a6Sopenharmony_ci        pointerAction = pointerEvent->GetPointerAction();
125c29fa5a6Sopenharmony_ci        MMI_HILOGD("pointerAction:%{public}d, actionTime:%{public}" PRId64 " frameTime_:%{public}" PRId64,
126c29fa5a6Sopenharmony_ci                   pointerAction, pointerEvent->GetActionTime(), frameTime_);
127c29fa5a6Sopenharmony_ci        switch (pointerAction) {
128c29fa5a6Sopenharmony_ci            case PointerEvent::POINTER_ACTION_DOWN:
129c29fa5a6Sopenharmony_ci            case PointerEvent::POINTER_ACTION_MOVE:
130c29fa5a6Sopenharmony_ci            case PointerEvent::POINTER_ACTION_UP:
131c29fa5a6Sopenharmony_ci                break;
132c29fa5a6Sopenharmony_ci            default: {
133c29fa5a6Sopenharmony_ci                MotionEvent event;
134c29fa5a6Sopenharmony_ci                event.InitializeFrom(pointerEvent);
135c29fa5a6Sopenharmony_ci                UpdateTouchState(event);
136c29fa5a6Sopenharmony_ci                return ERR_WOULD_BLOCK;
137c29fa5a6Sopenharmony_ci            }
138c29fa5a6Sopenharmony_ci        }
139c29fa5a6Sopenharmony_ci        inputEvent_.Reset();
140c29fa5a6Sopenharmony_ci        inputEvent_.InitializeFrom(pointerEvent);
141c29fa5a6Sopenharmony_ci
142c29fa5a6Sopenharmony_ci        EventDump("Input Event", inputEvent_);
143c29fa5a6Sopenharmony_ci    } else {
144c29fa5a6Sopenharmony_ci        inputEvent_.Reset();
145c29fa5a6Sopenharmony_ci    }
146c29fa5a6Sopenharmony_ci
147c29fa5a6Sopenharmony_ci    return ERR_OK;
148c29fa5a6Sopenharmony_ci}
149c29fa5a6Sopenharmony_ci
150c29fa5a6Sopenharmony_cibool EventResample::UpdateBatch(MotionEvent** outEvent, ErrCode &result)
151c29fa5a6Sopenharmony_ci{
152c29fa5a6Sopenharmony_ci    ssize_t batchIndex = FindBatch(inputEvent_.deviceId, inputEvent_.sourceType);
153c29fa5a6Sopenharmony_ci    if (batchIndex >= 0) {
154c29fa5a6Sopenharmony_ci        Batch& batch = batches_.at(batchIndex);
155c29fa5a6Sopenharmony_ci        if (CanAddSample(batch, inputEvent_)) {
156c29fa5a6Sopenharmony_ci            batch.samples.push_back(inputEvent_);
157c29fa5a6Sopenharmony_ci            MMI_HILOGD("Event added to batch, deviceId:%{public}d, sourceType:%{public}d, pointerAction:%{public}d",
158c29fa5a6Sopenharmony_ci                       inputEvent_.deviceId, inputEvent_.sourceType, inputEvent_.pointerAction);
159c29fa5a6Sopenharmony_ci            return true;
160c29fa5a6Sopenharmony_ci        }
161c29fa5a6Sopenharmony_ci    }
162c29fa5a6Sopenharmony_ci
163c29fa5a6Sopenharmony_ci    // Start a new batch
164c29fa5a6Sopenharmony_ci    if (PointerEvent::POINTER_ACTION_MOVE == inputEvent_.pointerAction) {
165c29fa5a6Sopenharmony_ci        Batch batch;
166c29fa5a6Sopenharmony_ci        batch.samples.push_back(inputEvent_);
167c29fa5a6Sopenharmony_ci        batches_.push_back(std::move(batch));
168c29fa5a6Sopenharmony_ci        return true;
169c29fa5a6Sopenharmony_ci    }
170c29fa5a6Sopenharmony_ci
171c29fa5a6Sopenharmony_ci    return false;
172c29fa5a6Sopenharmony_ci}
173c29fa5a6Sopenharmony_ci
174c29fa5a6Sopenharmony_civoid EventResample::UpdatePointerEvent(MotionEvent* outEvent)
175c29fa5a6Sopenharmony_ci{
176c29fa5a6Sopenharmony_ci    EventDump("Output Event", *outEvent);
177c29fa5a6Sopenharmony_ci    pointerEvent_->SetActionTime(outEvent->actionTime);
178c29fa5a6Sopenharmony_ci    pointerEvent_->SetPointerAction(outEvent->pointerAction);
179c29fa5a6Sopenharmony_ci    pointerEvent_->SetActionTime(outEvent->actionTime);
180c29fa5a6Sopenharmony_ci    pointerEvent_->SetId(outEvent->eventId);
181c29fa5a6Sopenharmony_ci
182c29fa5a6Sopenharmony_ci    for (auto &it : outEvent->pointers) {
183c29fa5a6Sopenharmony_ci        PointerEvent::PointerItem item;
184c29fa5a6Sopenharmony_ci        if (pointerEvent_->GetPointerItem(it.first, item)) {
185c29fa5a6Sopenharmony_ci            int32_t toolWindowX = item.GetToolWindowX();
186c29fa5a6Sopenharmony_ci            int32_t toolWindowY = item.GetToolWindowY();
187c29fa5a6Sopenharmony_ci            if (EventLogHelper::IsBetaVersion() && !pointerEvent_->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
188c29fa5a6Sopenharmony_ci                MMI_HILOGD("Output event: toolWindowX:%{public}d, toolWindowY:%{public}d", toolWindowX, toolWindowY);
189c29fa5a6Sopenharmony_ci            } else {
190c29fa5a6Sopenharmony_ci                MMI_HILOGD("Output event: toolWindowX:%d, toolWindowY:%d", toolWindowX, toolWindowY);
191c29fa5a6Sopenharmony_ci            }
192c29fa5a6Sopenharmony_ci            auto logicX = it.second.coordX;
193c29fa5a6Sopenharmony_ci            auto logicY = it.second.coordY;
194c29fa5a6Sopenharmony_ci            item.SetDisplayX(logicX);
195c29fa5a6Sopenharmony_ci            item.SetDisplayY(logicY);
196c29fa5a6Sopenharmony_ci
197c29fa5a6Sopenharmony_ci            auto windowXY = TransformSampleWindowXY(pointerEvent_, item, logicX, logicY);
198c29fa5a6Sopenharmony_ci            item.SetWindowX(windowXY.first);
199c29fa5a6Sopenharmony_ci            item.SetWindowY(windowXY.second);
200c29fa5a6Sopenharmony_ci
201c29fa5a6Sopenharmony_ci            if (PointerEvent::POINTER_ACTION_MOVE == outEvent->pointerAction) {
202c29fa5a6Sopenharmony_ci                item.SetPressed(true);
203c29fa5a6Sopenharmony_ci            } else if (PointerEvent::POINTER_ACTION_UP == outEvent->pointerAction) {
204c29fa5a6Sopenharmony_ci                item.SetPressed(false);
205c29fa5a6Sopenharmony_ci            } else {
206c29fa5a6Sopenharmony_ci                MMI_HILOGD("Output event:Pointer action:%{public}d", outEvent->pointerAction);
207c29fa5a6Sopenharmony_ci            }
208c29fa5a6Sopenharmony_ci            pointerEvent_->UpdatePointerItem(it.first, item);
209c29fa5a6Sopenharmony_ci        }
210c29fa5a6Sopenharmony_ci    }
211c29fa5a6Sopenharmony_ci}
212c29fa5a6Sopenharmony_ci
213c29fa5a6Sopenharmony_cistd::pair<int32_t, int32_t> EventResample::TransformSampleWindowXY(std::shared_ptr<PointerEvent> pointerEvent,
214c29fa5a6Sopenharmony_ci    PointerEvent::PointerItem &item, int32_t logicX, int32_t logicY)
215c29fa5a6Sopenharmony_ci{
216c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
217c29fa5a6Sopenharmony_ci    if (pointerEvent == nullptr) {
218c29fa5a6Sopenharmony_ci        return {logicX + item.GetToolWindowX(), logicY + item.GetToolWindowY()};
219c29fa5a6Sopenharmony_ci    }
220c29fa5a6Sopenharmony_ci    auto windows = WIN_MGR->GetWindowGroupInfoByDisplayId(pointerEvent->GetTargetDisplayId());
221c29fa5a6Sopenharmony_ci    for (const auto &window : windows) {
222c29fa5a6Sopenharmony_ci        if (pointerEvent->GetTargetWindowId() == window.id) {
223c29fa5a6Sopenharmony_ci            if (window.transform.empty()) {
224c29fa5a6Sopenharmony_ci                return {logicX + item.GetToolWindowX(), logicY + item.GetToolWindowY()};
225c29fa5a6Sopenharmony_ci            }
226c29fa5a6Sopenharmony_ci            auto windowXY = WIN_MGR->TransformWindowXY(window, logicX, logicY);
227c29fa5a6Sopenharmony_ci            auto windowX = static_cast<int32_t>(windowXY.first);
228c29fa5a6Sopenharmony_ci            auto windowY = static_cast<int32_t>(windowXY.second);
229c29fa5a6Sopenharmony_ci            return {windowX, windowY};
230c29fa5a6Sopenharmony_ci        }
231c29fa5a6Sopenharmony_ci    }
232c29fa5a6Sopenharmony_ci    return {logicX, logicY};
233c29fa5a6Sopenharmony_ci}
234c29fa5a6Sopenharmony_ci
235c29fa5a6Sopenharmony_ciErrCode EventResample::ConsumeBatch(int64_t frameTime, MotionEvent** outEvent)
236c29fa5a6Sopenharmony_ci{
237c29fa5a6Sopenharmony_ci    int32_t result = 0;
238c29fa5a6Sopenharmony_ci    for (size_t i = batches_.size(); i > 0;) {
239c29fa5a6Sopenharmony_ci        i--;
240c29fa5a6Sopenharmony_ci        Batch& batch = batches_.at(i);
241c29fa5a6Sopenharmony_ci        if (frameTime < 0) {
242c29fa5a6Sopenharmony_ci            result = ConsumeSamples(batch, batch.samples.size(), outEvent);
243c29fa5a6Sopenharmony_ci            batches_.erase(batches_.begin() + i);
244c29fa5a6Sopenharmony_ci            return result;
245c29fa5a6Sopenharmony_ci        }
246c29fa5a6Sopenharmony_ci
247c29fa5a6Sopenharmony_ci        int64_t sampleTime = frameTime;
248c29fa5a6Sopenharmony_ci        if (resampleTouch_) {
249c29fa5a6Sopenharmony_ci            sampleTime -= RESAMPLE_LATENCY;
250c29fa5a6Sopenharmony_ci        }
251c29fa5a6Sopenharmony_ci        ssize_t split = FindSampleNoLaterThan(batch, sampleTime);
252c29fa5a6Sopenharmony_ci        if (split < 0) {
253c29fa5a6Sopenharmony_ci            continue;
254c29fa5a6Sopenharmony_ci        }
255c29fa5a6Sopenharmony_ci
256c29fa5a6Sopenharmony_ci        result = ConsumeSamples(batch, split + 1, outEvent);
257c29fa5a6Sopenharmony_ci        const MotionEvent* next;
258c29fa5a6Sopenharmony_ci        if (batch.samples.empty()) {
259c29fa5a6Sopenharmony_ci            batches_.erase(batches_.begin() + i);
260c29fa5a6Sopenharmony_ci            next = NULL;
261c29fa5a6Sopenharmony_ci        } else {
262c29fa5a6Sopenharmony_ci            next = &batch.samples.at(0);
263c29fa5a6Sopenharmony_ci        }
264c29fa5a6Sopenharmony_ci        if (!result && resampleTouch_) {
265c29fa5a6Sopenharmony_ci            ResampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
266c29fa5a6Sopenharmony_ci        }
267c29fa5a6Sopenharmony_ci        return result;
268c29fa5a6Sopenharmony_ci    }
269c29fa5a6Sopenharmony_ci
270c29fa5a6Sopenharmony_ci    return ERR_WOULD_BLOCK;
271c29fa5a6Sopenharmony_ci}
272c29fa5a6Sopenharmony_ci
273c29fa5a6Sopenharmony_ciErrCode EventResample::ConsumeSamples(Batch& batch, size_t count, MotionEvent** outEvent)
274c29fa5a6Sopenharmony_ci{
275c29fa5a6Sopenharmony_ci    outputEvent_.Reset();
276c29fa5a6Sopenharmony_ci
277c29fa5a6Sopenharmony_ci    for (size_t i = 0; i < count; i++) {
278c29fa5a6Sopenharmony_ci        MotionEvent& event = batch.samples.at(i);
279c29fa5a6Sopenharmony_ci        UpdateTouchState(event);
280c29fa5a6Sopenharmony_ci        if (i > 0) {
281c29fa5a6Sopenharmony_ci            AddSample(&outputEvent_, &event);
282c29fa5a6Sopenharmony_ci        } else {
283c29fa5a6Sopenharmony_ci            outputEvent_.InitializeFrom(event);
284c29fa5a6Sopenharmony_ci        }
285c29fa5a6Sopenharmony_ci    }
286c29fa5a6Sopenharmony_ci    batch.samples.erase(batch.samples.begin(), batch.samples.begin() + count);
287c29fa5a6Sopenharmony_ci
288c29fa5a6Sopenharmony_ci    *outEvent = &outputEvent_;
289c29fa5a6Sopenharmony_ci
290c29fa5a6Sopenharmony_ci    return ERR_OK;
291c29fa5a6Sopenharmony_ci}
292c29fa5a6Sopenharmony_ci
293c29fa5a6Sopenharmony_civoid EventResample::AddSample(MotionEvent* outEvent, const MotionEvent* event)
294c29fa5a6Sopenharmony_ci{
295c29fa5a6Sopenharmony_ci    outEvent->actionTime = event->actionTime;
296c29fa5a6Sopenharmony_ci    for (auto &it : event->pointers) {
297c29fa5a6Sopenharmony_ci        outEvent->pointers[it.first] = it.second;
298c29fa5a6Sopenharmony_ci    }
299c29fa5a6Sopenharmony_ci}
300c29fa5a6Sopenharmony_ci
301c29fa5a6Sopenharmony_civoid EventResample::UpdateTouchState(MotionEvent &event)
302c29fa5a6Sopenharmony_ci{
303c29fa5a6Sopenharmony_ci    int32_t deviceId = event.deviceId;
304c29fa5a6Sopenharmony_ci    int32_t source = event.sourceType;
305c29fa5a6Sopenharmony_ci
306c29fa5a6Sopenharmony_ci    switch (event.pointerAction) {
307c29fa5a6Sopenharmony_ci        case PointerEvent::POINTER_ACTION_DOWN: {
308c29fa5a6Sopenharmony_ci            ssize_t idx = FindTouchState(deviceId, source);
309c29fa5a6Sopenharmony_ci            if (idx < 0) {
310c29fa5a6Sopenharmony_ci                TouchState newState;
311c29fa5a6Sopenharmony_ci                touchStates_.push_back(newState);
312c29fa5a6Sopenharmony_ci                idx = static_cast<ssize_t>(touchStates_.size()) - 1;
313c29fa5a6Sopenharmony_ci            }
314c29fa5a6Sopenharmony_ci            TouchState& touchState = touchStates_.at(idx);
315c29fa5a6Sopenharmony_ci            touchState.Initialize(deviceId, source);
316c29fa5a6Sopenharmony_ci            touchState.AddHistory(event);
317c29fa5a6Sopenharmony_ci            break;
318c29fa5a6Sopenharmony_ci        }
319c29fa5a6Sopenharmony_ci        case PointerEvent::POINTER_ACTION_MOVE: {
320c29fa5a6Sopenharmony_ci            ssize_t idx = FindTouchState(deviceId, source);
321c29fa5a6Sopenharmony_ci            if (idx >= 0) {
322c29fa5a6Sopenharmony_ci                TouchState& touchState = touchStates_.at(idx);
323c29fa5a6Sopenharmony_ci                touchState.AddHistory(event);
324c29fa5a6Sopenharmony_ci                RewriteMessage(touchState, event);
325c29fa5a6Sopenharmony_ci            }
326c29fa5a6Sopenharmony_ci            break;
327c29fa5a6Sopenharmony_ci        }
328c29fa5a6Sopenharmony_ci        case PointerEvent::POINTER_ACTION_UP:
329c29fa5a6Sopenharmony_ci        default: {
330c29fa5a6Sopenharmony_ci            ssize_t idx = FindTouchState(deviceId, source);
331c29fa5a6Sopenharmony_ci            if (idx >= 0) {
332c29fa5a6Sopenharmony_ci                TouchState& touchState = touchStates_.at(idx);
333c29fa5a6Sopenharmony_ci                RewriteMessage(touchState, event);
334c29fa5a6Sopenharmony_ci                touchStates_.erase(touchStates_.begin() + idx);
335c29fa5a6Sopenharmony_ci            }
336c29fa5a6Sopenharmony_ci            frameTime_ = 0;
337c29fa5a6Sopenharmony_ci            idx = FindBatch(deviceId, source);
338c29fa5a6Sopenharmony_ci            if (idx >= 0) {
339c29fa5a6Sopenharmony_ci                batches_.erase(batches_.begin() + idx);
340c29fa5a6Sopenharmony_ci            }
341c29fa5a6Sopenharmony_ci            break;
342c29fa5a6Sopenharmony_ci        }
343c29fa5a6Sopenharmony_ci    }
344c29fa5a6Sopenharmony_ci}
345c29fa5a6Sopenharmony_ci
346c29fa5a6Sopenharmony_civoid EventResample::ResampleTouchState(int64_t sampleTime, MotionEvent* event, const MotionEvent* next)
347c29fa5a6Sopenharmony_ci{
348c29fa5a6Sopenharmony_ci    if (!resampleTouch_ || (PointerEvent::SOURCE_TYPE_TOUCHSCREEN != event->sourceType)
349c29fa5a6Sopenharmony_ci                        || (PointerEvent::POINTER_ACTION_MOVE != event->pointerAction)) {
350c29fa5a6Sopenharmony_ci        return;
351c29fa5a6Sopenharmony_ci    }
352c29fa5a6Sopenharmony_ci
353c29fa5a6Sopenharmony_ci    ssize_t idx = FindTouchState(event->deviceId, event->sourceType);
354c29fa5a6Sopenharmony_ci    if (idx < 0) {
355c29fa5a6Sopenharmony_ci        return;
356c29fa5a6Sopenharmony_ci    }
357c29fa5a6Sopenharmony_ci
358c29fa5a6Sopenharmony_ci    TouchState &touchState = touchStates_.at(idx);
359c29fa5a6Sopenharmony_ci    if (touchState.historySize < 1) {
360c29fa5a6Sopenharmony_ci        return;
361c29fa5a6Sopenharmony_ci    }
362c29fa5a6Sopenharmony_ci
363c29fa5a6Sopenharmony_ci    // Ensure that the current sample has all of the pointers that need to be reported.
364c29fa5a6Sopenharmony_ci    const History* current = touchState.GetHistory(0);
365c29fa5a6Sopenharmony_ci    for (auto &it : event->pointers) {
366c29fa5a6Sopenharmony_ci        if (!current->HasPointerId(it.first)) {
367c29fa5a6Sopenharmony_ci            return;
368c29fa5a6Sopenharmony_ci        }
369c29fa5a6Sopenharmony_ci    }
370c29fa5a6Sopenharmony_ci
371c29fa5a6Sopenharmony_ci    // Find the data to use for resampling.
372c29fa5a6Sopenharmony_ci    const History* other;
373c29fa5a6Sopenharmony_ci    History future;
374c29fa5a6Sopenharmony_ci    float alpha;
375c29fa5a6Sopenharmony_ci    if (next) {
376c29fa5a6Sopenharmony_ci        // Interpolate between current sample and future sample.
377c29fa5a6Sopenharmony_ci        // So current->actionTime <= sampleTime <= future.actionTime.
378c29fa5a6Sopenharmony_ci        future.InitializeFrom(*next);
379c29fa5a6Sopenharmony_ci        other = &future;
380c29fa5a6Sopenharmony_ci        int64_t delta = future.actionTime - current->actionTime;
381c29fa5a6Sopenharmony_ci        if (delta < RESAMPLE_MIN_DELTA) {
382c29fa5a6Sopenharmony_ci            return;
383c29fa5a6Sopenharmony_ci        }
384c29fa5a6Sopenharmony_ci        alpha = static_cast<float>(sampleTime - current->actionTime) / delta;
385c29fa5a6Sopenharmony_ci    } else if (touchState.historySize >= HISTORY_SIZE_MAX) {
386c29fa5a6Sopenharmony_ci        // Extrapolate future sample using current sample and past sample.
387c29fa5a6Sopenharmony_ci        // So other->actionTime <= current->actionTime <= sampleTime.
388c29fa5a6Sopenharmony_ci        other = touchState.GetHistory(1);
389c29fa5a6Sopenharmony_ci        int64_t delta = current->actionTime - other->actionTime;
390c29fa5a6Sopenharmony_ci        if (delta < RESAMPLE_MIN_DELTA) {
391c29fa5a6Sopenharmony_ci            return;
392c29fa5a6Sopenharmony_ci        } else if (delta > RESAMPLE_MAX_DELTA) {
393c29fa5a6Sopenharmony_ci            return;
394c29fa5a6Sopenharmony_ci        }
395c29fa5a6Sopenharmony_ci        int64_t maxPredict = current->actionTime + std::min(delta / 2, RESAMPLE_MAX_PREDICTION);
396c29fa5a6Sopenharmony_ci        if (sampleTime > maxPredict) {
397c29fa5a6Sopenharmony_ci            sampleTime = maxPredict;
398c29fa5a6Sopenharmony_ci        }
399c29fa5a6Sopenharmony_ci        alpha = static_cast<float>(current->actionTime - sampleTime) / delta;
400c29fa5a6Sopenharmony_ci    } else {
401c29fa5a6Sopenharmony_ci        return;
402c29fa5a6Sopenharmony_ci    }
403c29fa5a6Sopenharmony_ci
404c29fa5a6Sopenharmony_ci    // Resample touch coordinates.
405c29fa5a6Sopenharmony_ci    ResampleCoordinates(sampleTime, event, touchState, current, other, alpha);
406c29fa5a6Sopenharmony_ci}
407c29fa5a6Sopenharmony_ci
408c29fa5a6Sopenharmony_civoid EventResample::ResampleCoordinates(int64_t sampleTime, MotionEvent* event, TouchState &touchState,
409c29fa5a6Sopenharmony_ci                                        const History* current, const History* other, float alpha)
410c29fa5a6Sopenharmony_ci{
411c29fa5a6Sopenharmony_ci    History oldLastResample;
412c29fa5a6Sopenharmony_ci    oldLastResample.InitializeFrom(touchState.lastResample);
413c29fa5a6Sopenharmony_ci    touchState.lastResample.actionTime = sampleTime;
414c29fa5a6Sopenharmony_ci
415c29fa5a6Sopenharmony_ci    for (auto &it : event->pointers) {
416c29fa5a6Sopenharmony_ci        uint32_t id = it.first;
417c29fa5a6Sopenharmony_ci        if (oldLastResample.HasPointerId(id) && touchState.RecentCoordinatesAreIdentical(id)) {
418c29fa5a6Sopenharmony_ci            auto lastItem = touchState.lastResample.pointers.find(id);
419c29fa5a6Sopenharmony_ci            if (lastItem != touchState.lastResample.pointers.end()) {
420c29fa5a6Sopenharmony_ci                auto oldLastItem = oldLastResample.pointers.find(id);
421c29fa5a6Sopenharmony_ci                lastItem->second.CopyFrom(oldLastItem->second);
422c29fa5a6Sopenharmony_ci            }
423c29fa5a6Sopenharmony_ci            continue;
424c29fa5a6Sopenharmony_ci        }
425c29fa5a6Sopenharmony_ci
426c29fa5a6Sopenharmony_ci        Pointer resampledCoords;
427c29fa5a6Sopenharmony_ci        const Pointer& currentCoords = current->GetPointerById(id);
428c29fa5a6Sopenharmony_ci        resampledCoords.CopyFrom(currentCoords);
429c29fa5a6Sopenharmony_ci        auto item = event->pointers.find(id);
430c29fa5a6Sopenharmony_ci        if (item == event->pointers.end()) {
431c29fa5a6Sopenharmony_ci            return;
432c29fa5a6Sopenharmony_ci        }
433c29fa5a6Sopenharmony_ci        if (other->HasPointerId(id) && ShouldResampleTool(item->second.toolType)) {
434c29fa5a6Sopenharmony_ci            const Pointer& otherCoords = other->GetPointerById(id);
435c29fa5a6Sopenharmony_ci            resampledCoords.coordX = CalcCoord(currentCoords.coordX, otherCoords.coordX, alpha);
436c29fa5a6Sopenharmony_ci            resampledCoords.coordY = CalcCoord(currentCoords.coordY, otherCoords.coordY, alpha);
437c29fa5a6Sopenharmony_ci        }
438c29fa5a6Sopenharmony_ci        item->second.CopyFrom(resampledCoords);
439c29fa5a6Sopenharmony_ci        event->actionTime = sampleTime;
440c29fa5a6Sopenharmony_ci    }
441c29fa5a6Sopenharmony_ci}
442c29fa5a6Sopenharmony_ci
443c29fa5a6Sopenharmony_cissize_t EventResample::FindBatch(int32_t deviceId, int32_t source) const
444c29fa5a6Sopenharmony_ci{
445c29fa5a6Sopenharmony_ci    ssize_t idx = 0;
446c29fa5a6Sopenharmony_ci    for (auto it = batches_.begin(); it < batches_.end(); ++it, ++idx) {
447c29fa5a6Sopenharmony_ci        const MotionEvent& head = it->samples.at(0);
448c29fa5a6Sopenharmony_ci        if ((head.deviceId == deviceId) && (head.sourceType == source)) {
449c29fa5a6Sopenharmony_ci            return idx;
450c29fa5a6Sopenharmony_ci        }
451c29fa5a6Sopenharmony_ci    }
452c29fa5a6Sopenharmony_ci    return -1;
453c29fa5a6Sopenharmony_ci}
454c29fa5a6Sopenharmony_ci
455c29fa5a6Sopenharmony_cissize_t EventResample::FindTouchState(int32_t deviceId, int32_t source) const
456c29fa5a6Sopenharmony_ci{
457c29fa5a6Sopenharmony_ci    ssize_t idx = 0;
458c29fa5a6Sopenharmony_ci    for (auto it = touchStates_.begin(); it < touchStates_.end(); ++it, ++idx) {
459c29fa5a6Sopenharmony_ci        if ((it->deviceId == deviceId) && (it->source == source)) {
460c29fa5a6Sopenharmony_ci            return idx;
461c29fa5a6Sopenharmony_ci        }
462c29fa5a6Sopenharmony_ci    }
463c29fa5a6Sopenharmony_ci    return -1;
464c29fa5a6Sopenharmony_ci}
465c29fa5a6Sopenharmony_ci
466c29fa5a6Sopenharmony_cibool EventResample::CanAddSample(const Batch &batch, MotionEvent &event)
467c29fa5a6Sopenharmony_ci{
468c29fa5a6Sopenharmony_ci    const MotionEvent& head = batch.samples.at(0);
469c29fa5a6Sopenharmony_ci    uint32_t pointerCount = event.pointerCount;
470c29fa5a6Sopenharmony_ci    int32_t pointerAction = event.pointerAction;
471c29fa5a6Sopenharmony_ci    if ((head.pointerCount != pointerCount) || (head.pointerAction != pointerAction)) {
472c29fa5a6Sopenharmony_ci        return false;
473c29fa5a6Sopenharmony_ci    }
474c29fa5a6Sopenharmony_ci
475c29fa5a6Sopenharmony_ci    return true;
476c29fa5a6Sopenharmony_ci}
477c29fa5a6Sopenharmony_ci
478c29fa5a6Sopenharmony_civoid EventResample::RewriteMessage(TouchState& state, MotionEvent &event)
479c29fa5a6Sopenharmony_ci{
480c29fa5a6Sopenharmony_ci    for (auto &it : event.pointers) {
481c29fa5a6Sopenharmony_ci        uint32_t id = it.first;
482c29fa5a6Sopenharmony_ci        if (state.lastResample.HasPointerId(id)) {
483c29fa5a6Sopenharmony_ci            if ((event.actionTime < state.lastResample.actionTime) || state.RecentCoordinatesAreIdentical(id)) {
484c29fa5a6Sopenharmony_ci                Pointer& msgCoords = it.second;
485c29fa5a6Sopenharmony_ci                const Pointer& resampleCoords = state.lastResample.GetPointerById(id);
486c29fa5a6Sopenharmony_ci                msgCoords.CopyFrom(resampleCoords);
487c29fa5a6Sopenharmony_ci            } else {
488c29fa5a6Sopenharmony_ci                state.lastResample.pointers.erase(id);
489c29fa5a6Sopenharmony_ci            }
490c29fa5a6Sopenharmony_ci        }
491c29fa5a6Sopenharmony_ci    }
492c29fa5a6Sopenharmony_ci}
493c29fa5a6Sopenharmony_ci
494c29fa5a6Sopenharmony_cissize_t EventResample::FindSampleNoLaterThan(const Batch& batch, int64_t time)
495c29fa5a6Sopenharmony_ci{
496c29fa5a6Sopenharmony_ci    size_t numSamples = batch.samples.size();
497c29fa5a6Sopenharmony_ci    size_t idx = 0;
498c29fa5a6Sopenharmony_ci    while ((idx < numSamples) && (batch.samples.at(idx).actionTime <= time)) {
499c29fa5a6Sopenharmony_ci        idx += 1;
500c29fa5a6Sopenharmony_ci    }
501c29fa5a6Sopenharmony_ci    return ssize_t(idx) - 1;
502c29fa5a6Sopenharmony_ci}
503c29fa5a6Sopenharmony_ci
504c29fa5a6Sopenharmony_cibool EventResample::ShouldResampleTool(int32_t toolType)
505c29fa5a6Sopenharmony_ci{
506c29fa5a6Sopenharmony_ci    switch (toolType) {
507c29fa5a6Sopenharmony_ci        case PointerEvent::TOOL_TYPE_FINGER:
508c29fa5a6Sopenharmony_ci        case PointerEvent::TOOL_TYPE_PEN:
509c29fa5a6Sopenharmony_ci            return true;
510c29fa5a6Sopenharmony_ci        default:
511c29fa5a6Sopenharmony_ci            return false;
512c29fa5a6Sopenharmony_ci    }
513c29fa5a6Sopenharmony_ci}
514c29fa5a6Sopenharmony_ci
515c29fa5a6Sopenharmony_civoid EventResample::PrintfDeviceName()
516c29fa5a6Sopenharmony_ci{
517c29fa5a6Sopenharmony_ci    auto device = INPUT_DEV_MGR->GetInputDevice(pointerEvent_->GetDeviceId());
518c29fa5a6Sopenharmony_ci    CHKPV(device);
519c29fa5a6Sopenharmony_ci    MMI_HILOGI("InputTracking id:%{public}d event created by:%{public}s", pointerEvent_->GetId(),
520c29fa5a6Sopenharmony_ci        device->GetName().c_str());
521c29fa5a6Sopenharmony_ci}
522c29fa5a6Sopenharmony_ci
523c29fa5a6Sopenharmony_ci} // namespace MMI
524c29fa5a6Sopenharmony_ci} // namespace OHOS
525