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