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