1 /*
2  * Copyright (c) 2024 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 "drag_smooth_processor.h"
17 
18 #include <utility>
19 
20 #include "devicestatus_common.h"
21 #include "include/util.h"
22 
23 #undef LOG_TAG
24 #define LOG_TAG "DragSmoothProcessor"
25 
26 namespace OHOS {
27 namespace Msdp {
28 namespace DeviceStatus {
29 namespace {
30 constexpr uint64_t ONE_MS_IN_NS { 1 * 1000 * 1000 }; // 1ms
31 constexpr int32_t RESAMPLE_COORD_TIME_THRESHOLD { 20 * 1000 * 1000 };  // 20ms
32 constexpr uint64_t INTERPOLATION_THRESHOLD { 100 * 1000 * 1000 }; // 100ms
33 }
InsertEvent(const DragMoveEvent & event)34 void DragSmoothProcessor::InsertEvent(const DragMoveEvent &event)
35 {
36     std::lock_guard<std::mutex> lock(mtx_);
37     moveEvents_.emplace_back(event);
38 }
39 
SmoothMoveEvent(uint64_t nanoTimestamp,uint64_t vSyncPeriod)40 DragMoveEvent DragSmoothProcessor::SmoothMoveEvent(uint64_t nanoTimestamp, uint64_t vSyncPeriod)
41 {
42     resampleTimeStamp_ = nanoTimestamp - vSyncPeriod + ONE_MS_IN_NS;
43     auto targetTimeStamp = resampleTimeStamp_;
44     std::vector<DragMoveEvent> currentEvents;
45     {
46         std::lock_guard<std::mutex> lock(mtx_);
47         currentEvents.swap(moveEvents_);
48     }
49     DragMoveEvent latestEvent = currentEvents.back();
50     auto resampleEvent = GetResampleEvent(historyEvents_, currentEvents, targetTimeStamp);
51     historyEvents_ = currentEvents;
52     return resampleEvent.has_value() ? resampleEvent.value() : latestEvent;
53 }
54 
ResetParameters()55 void DragSmoothProcessor::ResetParameters()
56 {
57     std::lock_guard<std::mutex> lock(mtx_);
58     moveEvents_.clear();
59     historyEvents_.clear();
60     resampleTimeStamp_ = 0;
61 }
62 
GetResampleEvent(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,uint64_t nanoTimestamp)63 std::optional<DragMoveEvent> DragSmoothProcessor::GetResampleEvent(const std::vector<DragMoveEvent>& history,
64     const std::vector<DragMoveEvent>& current, uint64_t nanoTimestamp)
65 {
66     auto event = Resample(history, current, nanoTimestamp);
67     DragMoveEvent nearestEvent = GetNearestEvent(current, nanoTimestamp);
68     return event.has_value() ? event.value() : nearestEvent;
69 }
70 
GetNearestEvent(const std::vector<DragMoveEvent> & events,uint64_t nanoTimestamp)71 DragMoveEvent DragSmoothProcessor::GetNearestEvent(const std::vector<DragMoveEvent>& events, uint64_t nanoTimestamp)
72 {
73     DragMoveEvent nearestEvent;
74     uint64_t gap = UINT64_MAX;
75     for (const auto &event : events) {
76         if (event.timestamp == nanoTimestamp) {
77             nearestEvent = event;
78             return nearestEvent;
79         }
80         if (event.timestamp > nanoTimestamp) {
81             if (event.timestamp - nanoTimestamp < gap) {
82                 gap = event.timestamp - nanoTimestamp;
83                 nearestEvent = event;
84             }
85         } else {
86             if (nanoTimestamp - event.timestamp < gap) {
87                 gap = nanoTimestamp - event.timestamp;
88                 nearestEvent = event;
89             }
90         }
91     }
92     return nearestEvent;
93 }
94 
Resample(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,uint64_t nanoTimestamp)95 std::optional<DragMoveEvent> DragSmoothProcessor::Resample(const std::vector<DragMoveEvent>& history,
96     const std::vector<DragMoveEvent>& current, uint64_t nanoTimestamp)
97 {
98     if (history.empty() || current.empty()) {
99         FI_HILOGW("history or current is empty, history size:%{public}zu, current size:%{public}zu,"
100             "nanoTimestamp:%{public}" PRId64, history.size(), current.size(), nanoTimestamp);
101         return std::nullopt;
102     }
103     DragMoveEvent latestEvent;
104     for (auto const &event : current) {
105         if (latestEvent.timestamp < event.timestamp) {
106             latestEvent = event;
107         }
108     }
109     if (nanoTimestamp > RESAMPLE_COORD_TIME_THRESHOLD + latestEvent.timestamp) {
110         FI_HILOGW("latestEvent is beyond the sampling range, use this this latest event, x:%{private}f, "
111             "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, sampling nanoTimestamp:%{public}" PRId64,
112             latestEvent.displayX, latestEvent.displayY, latestEvent.timestamp, latestEvent.displayId, nanoTimestamp);
113         return latestEvent;
114     }
115     auto historyAvgEvent = GetAvgCoordinate(history);
116     auto currentAvgEvent = GetAvgCoordinate(current);
117     DumpMoveEvent(history, current, historyAvgEvent, currentAvgEvent, latestEvent);
118     return GetInterpolatedEvent(historyAvgEvent, currentAvgEvent, nanoTimestamp);
119 }
120 
GetInterpolatedEvent(const DragMoveEvent & historyAvgEvent,const DragMoveEvent & currentAvgEvent,uint64_t nanoTimestamp)121 std::optional<DragMoveEvent> DragSmoothProcessor::GetInterpolatedEvent(const DragMoveEvent &historyAvgEvent,
122     const DragMoveEvent &currentAvgEvent, uint64_t nanoTimestamp)
123 {
124     if ((nanoTimestamp <= historyAvgEvent.timestamp) || (nanoTimestamp == currentAvgEvent.timestamp) ||
125         (currentAvgEvent.timestamp <= historyAvgEvent.timestamp) ||
126         ((currentAvgEvent.timestamp - historyAvgEvent.timestamp) > INTERPOLATION_THRESHOLD)) {
127             FI_HILOGW("No need linear interpolation, historyAvgEvent x:%{private}f, "
128             "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, currentAvgEvent x:%{private}f"
129             "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, nanoTimestamp: %{public}" PRId64,
130             historyAvgEvent.displayX, historyAvgEvent.displayY, historyAvgEvent.timestamp, historyAvgEvent.displayId,
131             currentAvgEvent.displayX, currentAvgEvent.displayY, currentAvgEvent.timestamp, currentAvgEvent.displayId,
132             nanoTimestamp);
133         return std::nullopt;
134     }
135     DragMoveEvent event;
136     if (nanoTimestamp < currentAvgEvent.timestamp) {
137         float alpha = static_cast<float>(nanoTimestamp - historyAvgEvent.timestamp) /
138             (currentAvgEvent.timestamp - historyAvgEvent.timestamp);
139         event.displayX = historyAvgEvent.displayX + alpha * (currentAvgEvent.displayX - historyAvgEvent.displayX);
140         event.displayY = historyAvgEvent.displayY + alpha * (currentAvgEvent.displayY - historyAvgEvent.displayY);
141         event.timestamp = nanoTimestamp;
142         event.displayId = currentAvgEvent.displayId;
143     } else if (nanoTimestamp > currentAvgEvent.timestamp) {
144         float alpha = static_cast<float>(nanoTimestamp - currentAvgEvent.timestamp) /
145             (currentAvgEvent.timestamp - historyAvgEvent.timestamp);
146         event.displayX = currentAvgEvent.displayX + alpha * (currentAvgEvent.displayX - historyAvgEvent.displayX);
147         event.displayY = currentAvgEvent.displayY + alpha * (currentAvgEvent.displayY - historyAvgEvent.displayY);
148         event.timestamp = nanoTimestamp;
149         event.displayId = currentAvgEvent.displayId;
150     }
151     return event;
152 }
153 
DumpMoveEvent(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,const DragMoveEvent & historyAvgEvent,const DragMoveEvent & currentAvgEvent,const DragMoveEvent & latestEvent)154 void DragSmoothProcessor::DumpMoveEvent(const std::vector<DragMoveEvent>& history,
155     const std::vector<DragMoveEvent>& current, const DragMoveEvent &historyAvgEvent,
156     const DragMoveEvent &currentAvgEvent, const DragMoveEvent &latestEvent)
157 {
158     for (const auto &event : history) {
159         FI_HILOGD("history event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
160             event.displayX, event.displayY, event.timestamp, event.displayId);
161     }
162     for (const auto &event : current) {
163         FI_HILOGD("current event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
164             event.displayX, event.displayY, event.timestamp, event.displayId);
165     }
166     FI_HILOGD("history average event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
167         historyAvgEvent.displayX, historyAvgEvent.displayY, historyAvgEvent.timestamp, historyAvgEvent.displayId);
168     FI_HILOGD("current average event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
169         currentAvgEvent.displayX, currentAvgEvent.displayY, currentAvgEvent.timestamp, currentAvgEvent.displayId);
170     FI_HILOGD("latest event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
171         latestEvent.displayX, latestEvent.displayY, latestEvent.timestamp, latestEvent.displayId);
172 }
173 
GetAvgCoordinate(const std::vector<DragMoveEvent> & events)174 DragMoveEvent DragSmoothProcessor::GetAvgCoordinate(const std::vector<DragMoveEvent>& events)
175 {
176     DragMoveEvent avgEvent;
177     if (events.empty()) {
178         FI_HILOGW("events is empty");
179         return avgEvent;
180     }
181     int32_t i = 0;
182     uint64_t lastTime = 0;
183     for (const auto &event : events) {
184         if ((lastTime == 0) || (lastTime != event.timestamp)) {
185             avgEvent.displayX += event.displayX;
186             avgEvent.displayY += event.displayY;
187             avgEvent.timestamp += event.timestamp;
188             avgEvent.displayId = event.displayId;
189             lastTime = event.timestamp;
190             i++;
191         }
192     }
193     if (i != 0) {
194         avgEvent.displayX /= i;
195         avgEvent.displayY /= i;
196         avgEvent.timestamp /= static_cast<uint64_t>(i);
197     }
198     return avgEvent;
199 }
200 } // namespace DeviceStatus
201 } // namespace Msdp
202 } // namespace OHOS