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 "knuckle_dynamic_drawing_manager.h"
17
18 #include "image/bitmap.h"
19 #include "image_source.h"
20 #include "image_type.h"
21 #include "image_utils.h"
22
23 #include "mmi_log.h"
24 #ifndef USE_ROSEN_DRAWING
25 #include "pipeline/rs_recording_canvas.h"
26 #else
27 #include "recording/recording_canvas.h"
28 #include "ui/rs_canvas_drawing_node.h"
29 #endif // USE_ROSEN_DRAWING
30 #include "parameters.h"
31 #include "render/rs_pixel_map_util.h"
32 #include "touch_drawing_manager.h"
33
34 #undef MMI_LOG_TAG
35 #define MMI_LOG_TAG "KnuckleDynamicDrawingManager"
36
37 namespace OHOS {
38 namespace MMI {
39 namespace {
40 const std::string IMAGE_POINTER_PENTAGRAM_PATH = "/system/etc/multimodalinput/mouse_icon/";
41 const std::string PENT_ICON_PATH = IMAGE_POINTER_PENTAGRAM_PATH + "Knuckle_Sprite_360.png";
42 constexpr int32_t DENSITY_BASELINE { 160 };
43 constexpr int32_t INDEPENDENT_INNER_PIXELS { 20 };
44 constexpr int32_t INDEPENDENT_OUTER_PIXELS { 21 };
45 constexpr int32_t INDEPENDENT_WIDTH_PIXELS { 2 };
46 constexpr int32_t CALCULATE_MIDDLE { 2 };
47 constexpr int32_t DEFAULT_VALUE { -1 };
48 constexpr int32_t MAX_POINTER_COLOR { 0x00ffff };
49 constexpr int32_t TIME_DIMENSION { 1000 };
50 constexpr int32_t PATH_COLOR { 0xFFCCCCCC };
51 constexpr int32_t MIN_POINT_SIZE { 1 };
52 constexpr float PAINT_STROKE_WIDTH { 10.0f };
53 constexpr float DOUBLE { 2.0f };
54 constexpr int32_t POINT_TOTAL_SIZE { 5 };
55 constexpr int32_t POINT_SYSTEM_SIZE { 200 };
56 constexpr int32_t MAX_DIVERGENCE_NUM { 10 };
57 constexpr int32_t DEFAULT_POINTER_SIZE { 1 };
58 constexpr int32_t DESIRED_SIZE { 80 };
59 constexpr int64_t DOUBLE_CLICK_INTERVAL_TIME_SLOW { 450000 };
60 constexpr int64_t WAIT_DOUBLE_CLICK_INTERVAL_TIME { 100000 };
61 constexpr float DOUBLE_CLICK_DISTANCE_LONG_CONFIG { 96.0f };
62 constexpr float VPR_CONFIG { 3.25f };
63 constexpr int32_t POW_SQUARE { 2 };
64 constexpr int32_t IN_DRAWING_TIME { 23000 };
65 constexpr uint64_t FOLD_SCREEN_MAIN_ID { 5 };
66 constexpr std::string_view SCREEN_READ_ENABLE { "1" };
67 } // namespace
68
KnuckleDynamicDrawingManager()69 KnuckleDynamicDrawingManager::KnuckleDynamicDrawingManager()
70 {
71 InitPointerPathPaint();
72 }
73
DecodeImageToPixelMap(const std::string & imagePath)74 std::shared_ptr<OHOS::Media::PixelMap> KnuckleDynamicDrawingManager::DecodeImageToPixelMap(const std::string &imagePath)
75 {
76 CALL_DEBUG_ENTER;
77 OHOS::Media::SourceOptions opts;
78 uint32_t ret = 0;
79 auto imageSource = OHOS::Media::ImageSource::CreateImageSource(imagePath, opts, ret);
80 CHKPP(imageSource);
81 std::set<std::string> formats;
82 ret = imageSource->GetSupportedFormats(formats);
83 OHOS::Media::DecodeOptions decodeOpts;
84 decodeOpts.desiredSize = {
85 .width = DESIRED_SIZE,
86 .height = DESIRED_SIZE
87 };
88
89 decodeOpts.SVGOpts.fillColor = {.isValidColor = true, .color = MAX_POINTER_COLOR};
90 decodeOpts.SVGOpts.strokeColor = {.isValidColor = true, .color = MAX_POINTER_COLOR};
91 std::shared_ptr<OHOS::Media::PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, ret);
92 CHKPL(pixelMap);
93 return pixelMap;
94 }
95
InitPointerPathPaint()96 void KnuckleDynamicDrawingManager::InitPointerPathPaint()
97 {
98 CALL_DEBUG_ENTER;
99 pixelMap_ = DecodeImageToPixelMap(PENT_ICON_PATH);
100 CHKPV(pixelMap_);
101 if (glowTraceSystem_ == nullptr) {
102 glowTraceSystem_ = std::make_shared<KnuckleGlowTraceSystem>(POINT_SYSTEM_SIZE, pixelMap_, MAX_DIVERGENCE_NUM);
103 }
104 pointerPathPaint_.setStyle(SkPaint::Style::kStroke_Style);
105 pointerPathPaint_.setStrokeJoin(SkPaint::Join::kRound_Join);
106 pointerPathPaint_.setStrokeCap(SkPaint::Cap::kRound_Cap);
107 pointerPathPaint_.setStrokeWidth(PAINT_STROKE_WIDTH);
108 pointerPathPaint_.setAntiAlias(true);
109 }
110
UpdateTrackColors()111 void KnuckleDynamicDrawingManager::UpdateTrackColors()
112 {
113 CALL_DEBUG_ENTER;
114 pointerPathPaint_.setColor(PATH_COLOR);
115 }
116
KnuckleDynamicDrawHandler(std::shared_ptr<PointerEvent> pointerEvent)117 void KnuckleDynamicDrawingManager::KnuckleDynamicDrawHandler(std::shared_ptr<PointerEvent> pointerEvent)
118 {
119 CALL_DEBUG_ENTER;
120 CHKPV(pointerEvent);
121 if (!IsSingleKnuckle(pointerEvent)) {
122 return;
123 }
124 auto displayId = pointerEvent->GetTargetDisplayId();
125 CreateTouchWindow(displayId);
126 if (CheckPointerAction(pointerEvent)) {
127 StartTouchDraw(pointerEvent);
128 }
129 }
130
IsSingleKnuckle(std::shared_ptr<PointerEvent> touchEvent)131 bool KnuckleDynamicDrawingManager::IsSingleKnuckle(std::shared_ptr<PointerEvent> touchEvent)
132 {
133 CALL_DEBUG_ENTER;
134 CHKPF(touchEvent);
135 auto id = touchEvent->GetPointerId();
136 PointerEvent::PointerItem item;
137 touchEvent->GetPointerItem(id, item);
138 auto itemToolType = item.GetToolType();
139 if (itemToolType != PointerEvent::TOOL_TYPE_KNUCKLE ||
140 touchEvent->GetPointerIds().size() != 1 || isRotate_) {
141 if (!traceControlPoints_.empty()) {
142 isStop_ = true;
143 isDrawing_ = true;
144 DestoryWindow();
145 } else if (isRotate_) {
146 isRotate_ = false;
147 if (item.GetToolType() == PointerEvent::TOOL_TYPE_KNUCKLE) {
148 return true;
149 }
150 }
151 return false;
152 }
153 return true;
154 }
155
CheckPointerAction(std::shared_ptr<PointerEvent> pointerEvent)156 bool KnuckleDynamicDrawingManager::CheckPointerAction(std::shared_ptr<PointerEvent> pointerEvent)
157 {
158 CALL_DEBUG_ENTER;
159 CHKPF(knuckleDrawMgr_);
160 if (knuckleDrawMgr_->GetScreenReadState() == SCREEN_READ_ENABLE) {
161 DestoryWindow();
162 }
163 size_t size = pointerEvent->GetPointerIds().size();
164 if (size > MIN_POINT_SIZE) {
165 pointerPath_.Reset();
166 CHKPF(glowTraceSystem_);
167 glowTraceSystem_->Clear();
168 return false;
169 }
170 switch (pointerEvent->GetPointerAction()) {
171 case PointerEvent::POINTER_ACTION_UP:
172 case PointerEvent::POINTER_ACTION_PULL_UP:
173 ProcessUpAndCancelEvent(pointerEvent);
174 break;
175 case PointerEvent::POINTER_ACTION_DOWN:
176 case PointerEvent::POINTER_ACTION_PULL_DOWN:
177 ProcessDownEvent(pointerEvent);
178 return true;
179 case PointerEvent::POINTER_ACTION_MOVE:
180 case PointerEvent::POINTER_ACTION_PULL_MOVE:
181 if (!isStop_ && !traceControlPoints_.empty()) {
182 ProcessMoveEvent(pointerEvent);
183 return true;
184 }
185 return false;
186 default:
187 return false;
188 }
189 return true;
190 }
191
StartTouchDraw(std::shared_ptr<PointerEvent> pointerEvent)192 void KnuckleDynamicDrawingManager::StartTouchDraw(std::shared_ptr<PointerEvent> pointerEvent)
193 {
194 CHKPV(pointerEvent);
195 int32_t ret = DrawGraphic(pointerEvent);
196 if (ret != RET_OK) {
197 MMI_HILOGD("Can't get enough pointers to draw");
198 return;
199 }
200 Rosen::RSTransaction::FlushImplicitTransaction();
201 }
202
ProcessUpAndCancelEvent(std::shared_ptr<PointerEvent> pointerEvent)203 void KnuckleDynamicDrawingManager::ProcessUpAndCancelEvent(std::shared_ptr<PointerEvent> pointerEvent)
204 {
205 CALL_DEBUG_ENTER;
206 CHKPV(glowTraceSystem_);
207 CHKPV(pointerEvent);
208 lastUpTime_ = pointerEvent->GetActionTime();
209 if (pointerPath_.IsValid()) {
210 auto id = pointerEvent->GetPointerId();
211 PointerEvent::PointerItem pointerItem;
212 pointerEvent->GetPointerItem(id, pointerItem);
213 auto displayXY = TOUCH_DRAWING_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
214 glowTraceSystem_->ResetDivergentPoints(displayXY.first, displayXY.second);
215 }
216 isDrawing_ = true;
217 DestoryWindow();
218 }
219
ProcessDownEvent(std::shared_ptr<PointerEvent> pointerEvent)220 void KnuckleDynamicDrawingManager::ProcessDownEvent(std::shared_ptr<PointerEvent> pointerEvent)
221 {
222 CALL_DEBUG_ENTER;
223 CHKPV(pointerEvent);
224 if (traceControlPoints_.empty()) {
225 for (int32_t i = 0; i < POINT_TOTAL_SIZE; i++) {
226 Rosen::Drawing::Point point = Rosen::Drawing::Point();
227 traceControlPoints_.emplace_back(point);
228 }
229 }
230 int64_t intervalTime = pointerEvent->GetActionTime() - lastUpTime_;
231 firstDownTime_ = pointerEvent->GetActionTime();
232 bool isTimeIntervalReady = intervalTime > 0 && intervalTime <= DOUBLE_CLICK_INTERVAL_TIME_SLOW;
233
234 UpdateTrackColors();
235 lastUpdateTimeMillis_ = pointerEvent->GetActionTime();
236 pointCounter_ = 0;
237 auto id = pointerEvent->GetPointerId();
238 PointerEvent::PointerItem pointerItem;
239 pointerEvent->GetPointerItem(id, pointerItem);
240 auto displayXY = TOUCH_DRAWING_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
241 float downToPrevDownDistance = static_cast<float>(sqrt(pow(lastDownX_ - displayXY.first, POW_SQUARE) +
242 pow(lastDownY_ - displayXY.second, POW_SQUARE)));
243 bool isDistanceReady = downToPrevDownDistance < DOUBLE_CLICK_DISTANCE_LONG_CONFIG * POW_SQUARE;
244 if (isTimeIntervalReady && isDistanceReady) {
245 MMI_HILOGE("Take a screenshot");
246 isDrawing_ = true;
247 isStop_ = true;
248 return;
249 }
250 lastDownX_ = displayXY.first;
251 lastDownY_ = displayXY.second;
252 traceControlPoints_[pointCounter_].Set(displayXY.first, displayXY.second);
253 isStop_ = false;
254 }
255
ProcessMoveEvent(std::shared_ptr<PointerEvent> pointerEvent)256 void KnuckleDynamicDrawingManager::ProcessMoveEvent(std::shared_ptr<PointerEvent> pointerEvent)
257 {
258 CALL_DEBUG_ENTER;
259 CHKPV(pointerEvent);
260 pointCounter_++;
261 if (pointCounter_ >= POINT_TOTAL_SIZE) {
262 MMI_HILOGE("traceControlPoints_ index out of size");
263 return;
264 }
265 auto id = pointerEvent->GetPointerId();
266 PointerEvent::PointerItem pointerItem;
267 pointerEvent->GetPointerItem(id, pointerItem);
268 auto displayXY = TOUCH_DRAWING_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
269 traceControlPoints_[pointCounter_].Set(displayXY.first, displayXY.second);
270 int pointIndex4 = 4;
271 bool draw = (pointerEvent->GetActionTime() - firstDownTime_) > WAIT_DOUBLE_CLICK_INTERVAL_TIME;
272 if (pointCounter_ == pointIndex4) {
273 int pointIndex0 = 0;
274 int pointIndex1 = 1;
275 int pointIndex2 = 2;
276 int pointIndex3 = 3;
277
278 traceControlPoints_[pointIndex3].Set(
279 (traceControlPoints_[pointIndex2].GetX() + traceControlPoints_[pointIndex4].GetX()) / DOUBLE,
280 (traceControlPoints_[pointIndex2].GetY() + traceControlPoints_[pointIndex4].GetY()) / DOUBLE);
281 // Add a cubic Bezier from pt[0] to pt[3] with control pointspt[1] and pt[2]
282 pointerPath_.MoveTo (traceControlPoints_[pointIndex0].GetX(), traceControlPoints_[pointIndex0].GetY());
283 pointerPath_.CubicTo(traceControlPoints_[pointIndex1].GetX(), traceControlPoints_[pointIndex1].GetY(),
284 traceControlPoints_[pointIndex2].GetX(), traceControlPoints_[pointIndex2].GetY(),
285 traceControlPoints_[pointIndex3].GetX(), traceControlPoints_[pointIndex3].GetY());
286 traceControlPoints_[pointIndex0].Set(traceControlPoints_[pointIndex3].GetX(),
287 traceControlPoints_[pointIndex3].GetY());
288 traceControlPoints_[pointIndex1].Set (traceControlPoints_[pointIndex4].GetX(),
289 traceControlPoints_[pointIndex4].GetY());
290 pointCounter_ = 1;
291 // Add glowing particles onto the last path segment that was drawn
292 int64_t now = pointerEvent->GetActionTime();
293 if (draw) {
294 glowTraceSystem_->AddGlowPoints(pointerPath_, (now - lastUpdateTimeMillis_) / TIME_DIMENSION);
295 }
296 pointerPath_.Reset();
297 lastUpdateTimeMillis_ = now;
298 }
299 if (draw) {
300 glowTraceSystem_->ResetDivergentPoints(displayXY.first, displayXY.second);
301 isDrawing_ = false;
302 }
303 }
304
UpdateDisplayInfo(const DisplayInfo & displayInfo)305 void KnuckleDynamicDrawingManager::UpdateDisplayInfo(const DisplayInfo& displayInfo)
306 {
307 CALL_DEBUG_ENTER;
308 if (displayInfo_.direction != displayInfo.direction) {
309 MMI_HILOGD("DisplayInfo direction change");
310 isRotate_ = true;
311 }
312 scaleW_ = displayInfo.width > displayInfo.height ? displayInfo.width : displayInfo.height;
313 scaleH_ = displayInfo.width > displayInfo.height ? displayInfo.width : displayInfo.height;
314 displayInfo_ = displayInfo;
315 }
316
SetKnuckleDrawingManager(std::shared_ptr<KnuckleDrawingManager> knuckleDrawMgr)317 void KnuckleDynamicDrawingManager::SetKnuckleDrawingManager(std::shared_ptr<KnuckleDrawingManager> knuckleDrawMgr)
318 {
319 CALL_DEBUG_ENTER;
320 knuckleDrawMgr_ = knuckleDrawMgr;
321 }
322
DrawGraphic(std::shared_ptr<PointerEvent> pointerEvent)323 int32_t KnuckleDynamicDrawingManager::DrawGraphic(std::shared_ptr<PointerEvent> pointerEvent)
324 {
325 CALL_DEBUG_ENTER;
326 CHKPR(pointerEvent, RET_ERR);
327 CHKPR(canvasNode_, RET_ERR);
328 glowTraceSystem_->Update();
329 if ((pointerEvent->GetActionTime() - isInDrawingTime_) > IN_DRAWING_TIME) {
330 isInDrawingTime_ = pointerEvent->GetActionTime();
331 } else {
332 return RET_ERR;
333 }
334 #ifndef USE_ROSEN_DRAWING
335 auto canvas = static_cast<Rosen::RSRecordingCanvas *>(canvasNode_->
336 BeginRecording(scaleW_, scaleH_));
337 #else
338 auto canvas = static_cast<Rosen::ExtendRecordingCanvas *>(canvasNode_->
339 BeginRecording(scaleW_, scaleH_));
340 #endif // USE_ROSEN_DRAWING
341
342 CHKPR(canvas, RET_ERR);
343
344 if (!isDrawing_) {
345 glowTraceSystem_->Draw(canvas);
346 }
347 canvasNode_->ResetSurface(scaleW_, scaleH_);
348 canvasNode_->FinishRecording();
349 return RET_OK;
350 }
351
CreateTouchWindow(const int32_t displayId)352 void KnuckleDynamicDrawingManager::CreateTouchWindow(const int32_t displayId)
353 {
354 CALL_DEBUG_ENTER;
355 if (surfaceNode_ != nullptr) {
356 MMI_HILOGD("surfaceNode_ is already exist");
357 return;
358 }
359 Rosen::RSSurfaceNodeConfig surfaceNodeConfig;
360 surfaceNodeConfig.SurfaceNodeName = "knuckle dynamic window";
361 Rosen::RSSurfaceNodeType surfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE;
362 surfaceNode_ = Rosen::RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType);
363 CHKPV(surfaceNode_);
364
365 surfaceNode_->SetSkipLayer(true);
366 surfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT_FILL);
367 surfaceNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
368 surfaceNode_->SetBounds(0, 0, scaleW_, scaleH_);
369 surfaceNode_->SetFrame(0, 0, scaleW_, scaleH_);
370
371 #ifndef USE_ROSEN_DRAWING
372 surfaceNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
373 #else
374 surfaceNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT);
375 #endif // USE_ROSEN_DRAWING
376
377 screenId_ = static_cast<uint64_t>(displayId);
378 surfaceNode_->SetRotation(0);
379
380 CreateCanvasNode();
381 surfaceNode_->AddChild(canvasNode_, DEFAULT_VALUE);
382 if (displayInfo_.displayMode == DisplayMode::MAIN) {
383 screenId_ = FOLD_SCREEN_MAIN_ID;
384 }
385 MMI_HILOGI("screenId_: %{public}" PRIu64, screenId_);
386 surfaceNode_->AttachToDisplay(screenId_);
387 CHKPV(knuckleDrawMgr_);
388 if (knuckleDrawMgr_->CheckRotatePolicy(displayInfo_)) {
389 knuckleDrawMgr_->RotationCanvasNode(canvasNode_, displayInfo_);
390 }
391 canvasNode_->ResetSurface(scaleW_, scaleH_);
392 Rosen::RSTransaction::FlushImplicitTransaction();
393 }
394
CreateCanvasNode()395 void KnuckleDynamicDrawingManager::CreateCanvasNode()
396 {
397 CALL_DEBUG_ENTER;
398 canvasNode_ = Rosen::RSCanvasDrawingNode::Create();
399 CHKPV(canvasNode_);
400 canvasNode_->SetBounds(0, 0, scaleW_, scaleH_);
401 canvasNode_->SetFrame(0, 0, scaleW_, scaleH_);
402
403 #ifndef USE_ROSEN_DRAWING
404 canvasNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
405 #else
406 canvasNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT);
407 #endif // USE_ROSEN_DRAWING
408 canvasNode_->SetCornerRadius(1);
409 canvasNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
410 canvasNode_->SetRotation(0);
411 }
412
DestoryWindow()413 void KnuckleDynamicDrawingManager::DestoryWindow()
414 {
415 CALL_DEBUG_ENTER;
416 traceControlPoints_.clear();
417 pointerPath_.Reset();
418 if (glowTraceSystem_ != nullptr) {
419 glowTraceSystem_->Clear();
420 }
421 CHKPV(canvasNode_);
422 #ifndef USE_ROSEN_DRAWING
423 auto canvas = static_cast<Rosen::RSRecordingCanvas *>(canvasNode_->
424 BeginRecording(scaleW_, scaleH_));
425 #else
426 auto canvas = static_cast<Rosen::ExtendRecordingCanvas *>(canvasNode_->
427 BeginRecording(scaleW_, scaleH_));
428 #endif // USE_ROSEN_DRAWING
429 CHKPV(canvas);
430 canvas->Clear();
431 canvasNode_->FinishRecording();
432 CHKPV(surfaceNode_);
433 surfaceNode_->DetachToDisplay(screenId_);
434 surfaceNode_->RemoveChild(canvasNode_);
435 canvasNode_->ResetSurface(scaleW_, scaleH_);
436 canvasNode_.reset();
437 surfaceNode_.reset();
438 Rosen::RSTransaction::FlushImplicitTransaction();
439 }
440 } // namespace MMI
441 } // namespace OHOS
442