1 /*
2  * Copyright (c) 2023 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 "core/components_ng/pattern/window_scene/scene/system_window_scene.h"
17 
18 #include "ui/rs_canvas_node.h"
19 #include "ui/rs_surface_node.h"
20 
21 #include "adapter/ohos/entrance/mmi_event_convertor.h"
22 #include "core/components_ng/pattern/window_scene/helper/window_scene_helper.h"
23 #include "core/components_ng/pattern/window_scene/scene/window_event_process.h"
24 #include "core/components_ng/render/adapter/rosen_render_context.h"
25 #include "core/pipeline_ng/pipeline_context.h"
26 
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr uint32_t DELAY_TIME = 3000;
30 } // namespace
31 
SystemWindowScene(const sptr<Rosen::Session> & session)32 SystemWindowScene::SystemWindowScene(const sptr<Rosen::Session>& session) : session_(session)
33 {
34     boundsChangedCallback_ = [weakThis = WeakClaim(this)](const Rosen::Vector4f& bounds) {
35         auto self = weakThis.Upgrade();
36         CHECK_NULL_VOID(self);
37         self->OnBoundsChanged(bounds);
38     };
39 }
40 
GetSession()41 sptr<Rosen::Session> SystemWindowScene::GetSession()
42 {
43     return session_;
44 }
45 
OnBoundsChanged(const Rosen::Vector4f & bounds)46 void SystemWindowScene::OnBoundsChanged(const Rosen::Vector4f& bounds)
47 {
48     Rosen::WSRect windowRect {
49         .posX_ = std::round(bounds.x_),
50         .posY_ = std::round(bounds.y_),
51         .width_ = std::round(bounds.z_),
52         .height_ = std::round(bounds.w_),
53     };
54 
55     CHECK_NULL_VOID(session_);
56     Rosen::WSRectF originBounds = {
57         .posX_ = bounds.x_,
58         .posY_ = bounds.y_,
59         .width_ = bounds.z_,
60         .height_ = bounds.w_,
61     };
62     session_->SetBounds(originBounds);
63     windowRect.posX_ = std::round(bounds.x_ + session_->GetOffsetX());
64     windowRect.posY_ = std::round(bounds.y_ + session_->GetOffsetY());
65     auto ret = session_->UpdateRect(windowRect, Rosen::SizeChangeReason::UNDEFINED, "OnBoundsChanged");
66     if (ret != Rosen::WSError::WS_OK) {
67         TAG_LOGI(AceLogTag::ACE_WINDOW_SCENE, "Update rect failed, id: %{public}d, ret: %{public}d",
68             session_->GetPersistentId(), static_cast<int32_t>(ret));
69     }
70 }
71 
OnVisibleChange(bool visible)72 void SystemWindowScene::OnVisibleChange(bool visible)
73 {
74     CHECK_NULL_VOID(session_);
75     TAG_LOGI(AceLogTag::ACE_WINDOW_SCENE, "Visibility of %{public}s[id:%{public}d] changed: %{public}s",
76         session_->GetSessionInfo().bundleName_.c_str(), session_->GetPersistentId(), visible ? "visible" : "invisible");
77     if (visible && session_->NeedCheckContextTransparent()) {
78         PostCheckContextTransparentTask();
79     } else if (session_->NeedCheckContextTransparent()) {
80         checkContextTransparentTask_.Cancel();
81     }
82     if (SystemProperties::GetFaultInjectEnabled() && session_->NeedCheckContextTransparent()) {
83         PostFaultInjectTask();
84     }
85     HandleVisibleChangeCallback(visible);
86 }
87 
OnAttachToFrameNode()88 void SystemWindowScene::OnAttachToFrameNode()
89 {
90     CHECK_NULL_VOID(session_);
91     auto host = GetHost();
92     CHECK_NULL_VOID(host);
93     ACE_SCOPED_TRACE("OnAttachToFrameNode[id:%d][self:%d][type:%d][name:%s]",
94         session_->GetPersistentId(), host->GetId(), session_->GetWindowType(), session_->GetWindowName().c_str());
95     TAG_LOGI(AceLogTag::ACE_WINDOW_SCENE,
96         "OnAttachToFrameNode id: %{public}d, node id: %{public}d, type: %{public}d, name: %{public}s",
97         session_->GetPersistentId(), host->GetId(), session_->GetWindowType(), session_->GetWindowName().c_str());
98 
99     host->SetWindowBoundary();
100     session_->SetUINodeId(host->GetAccessibilityId());
101     auto surfaceNode = session_->GetSurfaceNode();
102     CHECK_NULL_VOID(surfaceNode);
103     auto context = AceType::DynamicCast<NG::RosenRenderContext>(host->GetRenderContext());
104     CHECK_NULL_VOID(context);
105     context->SetRSNode(surfaceNode);
106     surfaceNode->SetBoundsChangedCallback(boundsChangedCallback_);
107 
108     auto mouseEventHub = host->GetOrCreateInputEventHub();
109     auto mouseCallback = [weakThis = WeakClaim(this), weakSession = wptr(session_)](MouseInfo& info) {
110         auto self = weakThis.Upgrade();
111         CHECK_NULL_VOID(self);
112         auto session = weakSession.promote();
113         CHECK_NULL_VOID(session);
114         const auto pointerEvent = info.GetPointerEvent();
115         CHECK_NULL_VOID(pointerEvent);
116         auto host = self->GetHost();
117         if (host != nullptr) {
118             DelayedSingleton<WindowEventProcess>::GetInstance()->ProcessWindowMouseEvent(
119                 host->GetId(), session, pointerEvent);
120             DelayedSingleton<WindowEventProcess>::GetInstance()->ProcessWindowDragEvent(
121                 host->GetId(), session, pointerEvent);
122         }
123         session->TransferPointerEvent(pointerEvent);
124     };
125     mouseEventHub->SetMouseEvent(std::move(mouseCallback));
126 
127     RegisterFocusCallback();
128     RegisterEventCallback();
129     RegisterResponseRegionCallback();
130 
131     if (session_->NeedCheckContextTransparent()) {
132         PostCheckContextTransparentTask();
133     }
134 }
135 
OnDetachFromFrameNode(FrameNode * frameNode)136 void SystemWindowScene::OnDetachFromFrameNode(FrameNode* frameNode)
137 {
138     CHECK_NULL_VOID(session_);
139     CHECK_NULL_VOID(frameNode);
140     ACE_SCOPED_TRACE("OnDetachFromFrameNode[id:%d][self:%d][type:%d][name:%s]",
141         session_->GetPersistentId(), frameNode->GetId(), session_->GetWindowType(), session_->GetWindowName().c_str());
142     TAG_LOGI(AceLogTag::ACE_WINDOW_SCENE,
143         "OnDetachFromFrameNode id: %{public}d, node id: %{public}d, type: %{public}d, name: %{public}s",
144         session_->GetPersistentId(), frameNode->GetId(), session_->GetWindowType(), session_->GetWindowName().c_str());
145     if (session_->NeedCheckContextTransparent()) {
146         checkContextTransparentTask_.Cancel();
147     }
148 }
149 
OnAttachToMainTree()150 void SystemWindowScene::OnAttachToMainTree()
151 {
152     auto host = GetHost();
153     CHECK_NULL_VOID(host);
154     auto context = host->GetRenderContext();
155     CHECK_NULL_VOID(context);
156     context->SetIsNeedRebuildRSTree(true);
157 }
158 
OnDetachFromMainTree()159 void SystemWindowScene::OnDetachFromMainTree()
160 {
161     auto host = GetHost();
162     CHECK_NULL_VOID(host);
163     auto context = host->GetRenderContext();
164     CHECK_NULL_VOID(context);
165     context->SetIsNeedRebuildRSTree(false);
166 }
167 
RegisterEventCallback()168 void SystemWindowScene::RegisterEventCallback()
169 {
170     CHECK_NULL_VOID(session_);
171     auto pointerEventCallback =
172         [weakThis = WeakClaim(this), instanceId = instanceId_](std::shared_ptr<MMI::PointerEvent> PointerEvent) {
173             ContainerScope Scope(instanceId);
174             auto pipelineContext = PipelineContext::GetCurrentContext();
175             if (!pipelineContext) {
176                 TAG_LOGE(AceLogTag::ACE_INPUTTRACKING,
177                     "PipelineContext GetCurrentContext null,id:%{public}d", PointerEvent->GetId());
178                 PointerEvent->MarkProcessed();
179                 return;
180             }
181             auto taskExecutor = pipelineContext->GetTaskExecutor();
182             if (!taskExecutor) {
183                 TAG_LOGE(AceLogTag::ACE_INPUTTRACKING, "taskExecutor is null,id:%{public}d", PointerEvent->GetId());
184                 PointerEvent->MarkProcessed();
185                 return;
186             }
187             taskExecutor->PostTask([weakThis, PointerEvent]() {
188                 auto self = weakThis.Upgrade();
189                 if (!self) {
190                     TAG_LOGE(AceLogTag::ACE_INPUTTRACKING,
191                         "weakThis Upgrade null,id:%{public}d", PointerEvent->GetId());
192                     PointerEvent->MarkProcessed();
193                     return;
194                 }
195                 auto host = self->GetHost();
196                 if (!host) {
197                     TAG_LOGE(AceLogTag::ACE_INPUTTRACKING,
198                         "GetHost null,id:%{public}d", PointerEvent->GetId());
199                     PointerEvent->MarkProcessed();
200                     return;
201                 }
202                 WindowSceneHelper::InjectPointerEvent(host, PointerEvent);
203             },
204                 TaskExecutor::TaskType::UI, "ArkUIWindowInjectPointerEvent", PriorityType::VIP);
205     };
206     session_->SetNotifySystemSessionPointerEventFunc(std::move(pointerEventCallback));
207 
208     auto keyEventCallback = [instanceId = instanceId_](std::shared_ptr<MMI::KeyEvent> KeyEvent,
209         bool isPreImeEvent) -> bool {
210         ContainerScope Scope(instanceId);
211         return WindowSceneHelper::InjectKeyEvent(KeyEvent, isPreImeEvent);
212     };
213     session_->SetNotifySystemSessionKeyEventFunc(std::move(keyEventCallback));
214 }
215 
RegisterResponseRegionCallback()216 void SystemWindowScene::RegisterResponseRegionCallback()
217 {
218     auto host = GetHost();
219     CHECK_NULL_VOID(host);
220     auto gestureHub = host->GetOrCreateGestureEventHub();
221     CHECK_NULL_VOID(gestureHub);
222 
223     auto touchCallback = [weakSession = wptr(session_)](TouchEventInfo& info) {
224         auto session = weakSession.promote();
225         CHECK_NULL_VOID(session);
226         const auto pointerEvent = info.GetPointerEvent();
227         CHECK_NULL_VOID(pointerEvent);
228         session->TransferPointerEvent(pointerEvent);
229     };
230     gestureHub->SetTouchEvent(std::move(touchCallback));
231 
232     auto responseRegionCallback = [weakThis = WeakClaim(this), weakSession = wptr(session_)](
233         const std::vector<DimensionRect>& responseRegion) {
234         auto self = weakThis.Upgrade();
235         CHECK_NULL_VOID(self);
236         auto session = weakSession.promote();
237         CHECK_NULL_VOID(session);
238         std::vector<Rosen::Rect> hotAreas;
239         for (auto& rect : responseRegion) {
240             Rosen::Rect windowRect {
241                 .posX_ = std::round(rect.GetOffset().GetX().Value()),
242                 .posY_ = std::round(rect.GetOffset().GetY().Value()),
243                 .width_ = std::round(rect.GetWidth().Value()),
244                 .height_ = std::round(rect.GetHeight().Value()),
245             };
246             hotAreas.push_back(windowRect);
247         }
248         session->SetTouchHotAreas(hotAreas);
249     };
250     gestureHub->SetResponseRegionFunc(responseRegionCallback);
251 }
252 
GetWindowPatternType() const253 uint32_t SystemWindowScene::GetWindowPatternType() const
254 {
255     return static_cast<uint32_t>(WindowPatternType::SYSTEM_WINDOW_SCENE);
256 }
257 
RegisterFocusCallback()258 void SystemWindowScene::RegisterFocusCallback()
259 {
260     CHECK_NULL_VOID(session_);
261 
262     auto requestFocusCallback = [weakThis = WeakClaim(this), frameNode = frameNode_, instanceId = instanceId_]() {
263         ContainerScope scope(instanceId);
264         auto pipelineContext = PipelineContext::GetCurrentContext();
265         CHECK_NULL_VOID(pipelineContext);
266         pipelineContext->SetFocusedWindowSceneNode(frameNode);
267         pipelineContext->PostAsyncEvent([weakThis]() {
268             auto pipeline = PipelineContext::GetCurrentContext();
269             CHECK_NULL_VOID(pipeline);
270             pipeline->SetIsFocusActive(false);
271             auto self = weakThis.Upgrade();
272             CHECK_NULL_VOID(self);
273             self->FocusViewShow();
274         }, "ArkUIWindowFocusViewShow", TaskExecutor::TaskType::UI);
275     };
276     session_->SetNotifyUIRequestFocusFunc(requestFocusCallback);
277 
278     auto lostFocusCallback = [weakThis = WeakClaim(this), instanceId = instanceId_]() {
279         ContainerScope scope(instanceId);
280         auto pipelineContext = PipelineContext::GetCurrentContext();
281         CHECK_NULL_VOID(pipelineContext);
282         pipelineContext->PostAsyncEvent([weakThis]() {
283             auto pipeline = PipelineContext::GetCurrentContext();
284             CHECK_NULL_VOID(pipeline);
285             auto self = weakThis.Upgrade();
286             CHECK_NULL_VOID(self);
287             CHECK_NULL_VOID(self->GetSession());
288             pipeline->RestoreDefault(self->GetSession()->GetPersistentId());
289         }, "ArkUIWindowLostFocus", TaskExecutor::TaskType::UI);
290     };
291     session_->SetNotifyUILostFocusFunc(lostFocusCallback);
292 }
293 
LostViewFocus()294 void SystemWindowScene::LostViewFocus()
295 {
296     TAG_LOGI(
297         AceLogTag::ACE_FOCUS, "Focus view: %{public}s/%{public}d lost focus", GetFrameName().c_str(), GetFrameId());
298     auto focusHub = GetFocusHub();
299     if (!focusHub || !focusHub->IsCurrentFocus()) {
300         return;
301     }
302     auto pipeline = PipelineContext::GetCurrentContext();
303     CHECK_NULL_VOID(pipeline);
304     auto screenNode = pipeline->GetScreenNode();
305     CHECK_NULL_VOID(screenNode);
306     auto screenNodeFocusHub = screenNode->GetFocusHub();
307     CHECK_NULL_VOID(screenNodeFocusHub);
308     screenNodeFocusHub->LostFocus(BlurReason::VIEW_SWITCH);
309 }
310 
RegisterVisibleChangeCallback(int32_t nodeId,std::function<void (bool)> callback)311 void SystemWindowScene::RegisterVisibleChangeCallback(
312     int32_t nodeId, std::function<void(bool)> callback)
313 {
314     CHECK_NULL_VOID(callback);
315     CHECK_NULL_VOID(session_);
316     TAG_LOGI(AceLogTag::ACE_WINDOW_SCENE, "RegisterVisibleChangeCallback %{public}s[id:%{public}d]"
317         " nodeId: %{public}d, mapSize: %{public}zu", session_->GetSessionInfo().bundleName_.c_str(),
318         session_->GetPersistentId(), nodeId, visibleChangeCallbackMap_.size());
319     visibleChangeCallbackMap_[nodeId] = callback;
320 }
321 
UnRegisterVisibleChangeCallback(int32_t nodeId)322 void SystemWindowScene::UnRegisterVisibleChangeCallback(int32_t nodeId)
323 {
324     CHECK_NULL_VOID(session_);
325     TAG_LOGI(AceLogTag::ACE_WINDOW_SCENE, "UnRegisterVisibleChangeCallback %{public}s[id:%{public}d]"
326         " nodeId: %{public}d, mapSize: %{public}zu", session_->GetSessionInfo().bundleName_.c_str(),
327         session_->GetPersistentId(), nodeId, visibleChangeCallbackMap_.size());
328     auto iter = visibleChangeCallbackMap_.find(nodeId);
329     if (iter == visibleChangeCallbackMap_.end()) {
330         return;
331     }
332 
333     visibleChangeCallbackMap_.erase(nodeId);
334 }
335 
HandleVisibleChangeCallback(bool visible)336 void SystemWindowScene::HandleVisibleChangeCallback(bool visible)
337 {
338     for (const auto& item : visibleChangeCallbackMap_) {
339         item.second(visible);
340     }
341 }
342 
PostCheckContextTransparentTask()343 void SystemWindowScene::PostCheckContextTransparentTask()
344 {
345     checkContextTransparentTask_.Reset([weakThis = WeakClaim(this)]() {
346         auto self = weakThis.Upgrade();
347         CHECK_NULL_VOID(self);
348         CHECK_NULL_VOID(self->GetHost());
349         CHECK_NULL_VOID(self->session_);
350         if (self->session_->NeedCheckContextTransparent() && self->GetHost()->IsContextTransparent()) {
351             self->session_->NotifyContextTransparent();
352         }
353     });
354 
355     auto pipelineContext = PipelineContext::GetCurrentContext();
356     CHECK_NULL_VOID(pipelineContext);
357     auto taskExecutor = pipelineContext->GetTaskExecutor();
358     CHECK_NULL_VOID(taskExecutor);
359     taskExecutor->PostDelayedTask(std::move(checkContextTransparentTask_), TaskExecutor::TaskType::UI,
360         DELAY_TIME, "ArkUIWindowCheckContextTransparent");
361 }
362 
PostFaultInjectTask()363 void SystemWindowScene::PostFaultInjectTask()
364 {
365     auto task = ([weakThis = WeakClaim(this)]() {
366         auto self = weakThis.Upgrade();
367         CHECK_NULL_VOID(self);
368         auto host = self->GetHost();
369         CHECK_NULL_VOID(host);
370         auto renderContext = AceType::DynamicCast<NG::RosenRenderContext>(host->GetRenderContext());
371         renderContext->SetOpacity(0.0f);
372         host->MarkDirtyNode();
373     });
374 
375     auto pipelineContext = PipelineContext::GetCurrentContext();
376     CHECK_NULL_VOID(pipelineContext);
377     auto taskExecutor = pipelineContext->GetTaskExecutor();
378     CHECK_NULL_VOID(taskExecutor);
379     taskExecutor->PostDelayedTask(
380         std::move(task), TaskExecutor::TaskType::UI, DELAY_TIME, "ArkUIWindowFaultInject");
381 }
382 } // namespace OHOS::Ace::NG
383