1 /*
2  * Copyright (c) 2021-2022 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 "frameworks/bridge/declarative_frontend/jsview/js_interactable_view.h"
17 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
18 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
19 #endif
20 
21 #include "base/log/ace_scoring_log.h"
22 #include "base/log/log_wrapper.h"
23 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
24 #include "bridge/declarative_frontend/engine/functions/js_hover_function.h"
25 #include "bridge/declarative_frontend/engine/functions/js_key_function.h"
26 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
27 #include "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_frame_node_bridge.h"
28 #include "bridge/declarative_frontend/jsview/js_pan_handler.h"
29 #include "bridge/declarative_frontend/jsview/js_touch_handler.h"
30 #include "bridge/declarative_frontend/jsview/js_utils.h"
31 #include "bridge/declarative_frontend/view_stack_processor.h"
32 #include "core/common/container.h"
33 #include "core/components/gesture_listener/gesture_listener_component.h"
34 #include "core/components_ng/base/view_abstract_model.h"
35 #include "core/components_ng/base/view_stack_processor.h"
36 #include "core/gestures/click_recognizer.h"
37 #include "core/pipeline/base/single_child.h"
38 #include "core/pipeline/pipeline_context.h"
39 
40 #ifdef PLUGIN_COMPONENT_SUPPORTED
41 #include "core/common/plugin_manager.h"
42 #endif
43 
44 namespace OHOS::Ace::Framework {
45 
JsOnTouch(const JSCallbackInfo & args)46 void JSInteractableView::JsOnTouch(const JSCallbackInfo& args)
47 {
48     if (args[0]->IsUndefined() && IsDisableEventVersion()) {
49         ViewAbstractModel::GetInstance()->DisableOnTouch();
50         return;
51     }
52     if (!args[0]->IsFunction()) {
53         return;
54     }
55     EcmaVM* vm = args.GetVm();
56     CHECK_NULL_VOID(vm);
57     auto jsOnTouchFunc = JSRef<JSFunc>::Cast(args[0]);
58     if (jsOnTouchFunc->IsEmpty()) {
59         return;
60     }
61     auto jsOnTouchFuncLocalHandle = jsOnTouchFunc->GetLocalHandle();
62     auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
63     auto onTouch = [vm, execCtx = args.GetExecutionContext(),
64                        func = panda::CopyableGlobal(vm, jsOnTouchFuncLocalHandle),
65                        node = frameNode](TouchEventInfo& info) {
66         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
67         ACE_SCORING_EVENT("onTouch");
68         PipelineContext::SetCallBackNode(node);
69         auto eventObj = NG::FrameNodeBridge::CreateTouchEventInfo(vm, info);
70         panda::Local<panda::JSValueRef> params[1] = { eventObj };
71         func->Call(vm, func.ToLocal(), params, 1);
72     };
73     ViewAbstractModel::GetInstance()->SetOnTouch(std::move(onTouch));
74 }
75 
JsOnKey(const JSCallbackInfo & args)76 void JSInteractableView::JsOnKey(const JSCallbackInfo& args)
77 {
78     if (args[0]->IsUndefined() && IsDisableEventVersion()) {
79         ViewAbstractModel::GetInstance()->DisableOnKeyEvent();
80         return;
81     }
82     if (!args[0]->IsFunction()) {
83         return;
84     }
85     RefPtr<JsKeyFunction> JsOnKeyEvent = AceType::MakeRefPtr<JsKeyFunction>(JSRef<JSFunc>::Cast(args[0]));
86     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
87     auto onKeyEvent = [execCtx = args.GetExecutionContext(), func = std::move(JsOnKeyEvent), node = frameNode](
88                           KeyEventInfo& info) -> bool {
89         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, false);
90         ACE_SCORING_EVENT("onKey");
91         PipelineContext::SetCallBackNode(node);
92         auto ret = func->ExecuteWithValue(info);
93         return ret->IsBoolean() ? ret->ToBoolean() : false;
94     };
95     ViewAbstractModel::GetInstance()->SetOnKeyEvent(std::move(onKeyEvent));
96 }
97 
JsOnKeyPreIme(const JSCallbackInfo & args)98 void JSInteractableView::JsOnKeyPreIme(const JSCallbackInfo& args)
99 {
100     if (args[0]->IsUndefined()) {
101         ViewAbstractModel::GetInstance()->DisableOnKeyPreIme();
102         return;
103     }
104     if (!args[0]->IsFunction()) {
105         return;
106     }
107     RefPtr<JsKeyFunction> JsOnPreImeEvent = AceType::MakeRefPtr<JsKeyFunction>(JSRef<JSFunc>::Cast(args[0]));
108     auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
109     auto onPreImeEvent = [execCtx = args.GetExecutionContext(), func = std::move(JsOnPreImeEvent), node = frameNode](
110                           KeyEventInfo& info) -> bool {
111         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, false);
112         ACE_SCORING_EVENT("onKeyPreIme");
113         PipelineContext::SetCallBackNode(node);
114         auto ret = func->ExecuteWithValue(info);
115         return ret->IsBoolean() ? ret->ToBoolean() : false;
116     };
117     ViewAbstractModel::GetInstance()->SetOnKeyPreIme(std::move(onPreImeEvent));
118 }
119 
JsOnHover(const JSCallbackInfo & info)120 void JSInteractableView::JsOnHover(const JSCallbackInfo& info)
121 {
122     if (info[0]->IsUndefined() && IsDisableEventVersion()) {
123         ViewAbstractModel::GetInstance()->DisableOnHover();
124         return;
125     }
126     if (!info[0]->IsFunction()) {
127         return;
128     }
129     RefPtr<JsHoverFunction> jsOnHoverFunc = AceType::MakeRefPtr<JsHoverFunction>(JSRef<JSFunc>::Cast(info[0]));
130     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
131     auto onHover = [execCtx = info.GetExecutionContext(), func = std::move(jsOnHoverFunc), node = frameNode](
132                        bool isHover, HoverInfo& hoverInfo) {
133         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
134         ACE_SCORING_EVENT("onHover");
135         PipelineContext::SetCallBackNode(node);
136         func->HoverExecute(isHover, hoverInfo);
137     };
138     ViewAbstractModel::GetInstance()->SetOnHover(std::move(onHover));
139 }
140 
JsOnPan(const JSCallbackInfo & args)141 void JSInteractableView::JsOnPan(const JSCallbackInfo& args)
142 {
143     if (args[0]->IsObject()) {
144 #ifndef NG_BUILD
145         JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
146         JSPanHandler* handler = obj->Unwrap<JSPanHandler>();
147         if (handler) {
148             handler->CreateComponent(args);
149         }
150 #endif
151     }
152 }
153 
JsOnDelete(const JSCallbackInfo & info)154 void JSInteractableView::JsOnDelete(const JSCallbackInfo& info)
155 {
156     if (info[0]->IsFunction()) {
157         RefPtr<JsFunction> jsOnDeleteFunc =
158             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
159         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
160         auto onDelete = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDeleteFunc), node = frameNode]() {
161             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
162             ACE_SCORING_EVENT("onDelete");
163             PipelineContext::SetCallBackNode(node);
164             func->Execute();
165         };
166         ViewAbstractModel::GetInstance()->SetOnDelete(std::move(onDelete));
167     }
168 }
169 
JsTouchable(const JSCallbackInfo & info)170 void JSInteractableView::JsTouchable(const JSCallbackInfo& info)
171 {
172     if (info[0]->IsBoolean()) {
173         ViewAbstractModel::GetInstance()->SetTouchable(info[0]->ToBoolean());
174     }
175 }
176 
JsMonopolizeEvents(const JSCallbackInfo & info)177 void JSInteractableView::JsMonopolizeEvents(const JSCallbackInfo& info)
178 {
179     if (info[0]->IsBoolean()) {
180         ViewAbstractModel::GetInstance()->SetMonopolizeEvents(info[0]->ToBoolean());
181     } else {
182         ViewAbstractModel::GetInstance()->SetMonopolizeEvents(false);
183     }
184 }
185 
JsOnClick(const JSCallbackInfo & info)186 void JSInteractableView::JsOnClick(const JSCallbackInfo& info)
187 {
188     JSRef<JSVal> jsOnClickVal = info[0];
189     if (jsOnClickVal->IsUndefined() && IsDisableEventVersion()) {
190         ViewAbstractModel::GetInstance()->DisableOnClick();
191         return;
192     }
193     if (!jsOnClickVal->IsFunction()) {
194         return;
195     }
196     auto frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
197     WeakPtr<NG::FrameNode> weak = AceType::WeakClaim(frameNode);
198     auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(jsOnClickVal));
199     auto onTap = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = weak](GestureEvent& info) {
200         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
201         ACE_SCORING_EVENT("onClick");
202         PipelineContext::SetCallBackNode(node);
203         func->Execute(info);
204 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
205         ReportClickEvent(node);
206 #endif
207     };
208     auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = weak](
209                        const ClickInfo* info) {
210         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
211         ACE_SCORING_EVENT("onClick");
212         PipelineContext::SetCallBackNode(node);
213         func->Execute(*info);
214 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
215         ReportClickEvent(node);
216 #endif
217     };
218 
219     double distanceThreshold = std::numeric_limits<double>::infinity();
220     if (info.Length() > 1 && info[1]->IsNumber()) {
221         distanceThreshold = info[1]->ToNumber<double>();
222     }
223     distanceThreshold = Dimension(distanceThreshold, DimensionUnit::VP).ConvertToPx();
224 
225     ViewAbstractModel::GetInstance()->SetOnClick(std::move(onTap), std::move(onClick), distanceThreshold);
226     CHECK_NULL_VOID(frameNode);
227     auto focusHub = frameNode->GetOrCreateFocusHub();
228     CHECK_NULL_VOID(focusHub);
229     focusHub->SetFocusable(true, false);
230 }
231 
SetFocusable(bool focusable)232 void JSInteractableView::SetFocusable(bool focusable)
233 {
234     ViewAbstractModel::GetInstance()->SetFocusable(focusable);
235 }
236 
SetFocusNode(bool isFocusNode)237 void JSInteractableView::SetFocusNode(bool isFocusNode)
238 {
239     ViewAbstractModel::GetInstance()->SetFocusNode(isFocusNode);
240 }
241 
JsOnAppear(const JSCallbackInfo & info)242 void JSInteractableView::JsOnAppear(const JSCallbackInfo& info)
243 {
244     if (info[0]->IsUndefined() && IsDisableEventVersion()) {
245         ViewAbstractModel::GetInstance()->DisableOnAppear();
246         return;
247     }
248     if (info[0]->IsFunction()) {
249         RefPtr<JsFunction> jsOnAppearFunc =
250             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
251         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
252         auto onAppear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc), node = frameNode]() {
253             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
254             ACE_SCORING_EVENT("onAppear");
255             PipelineContext::SetCallBackNode(node);
256             func->Execute();
257         };
258         ViewAbstractModel::GetInstance()->SetOnAppear(std::move(onAppear));
259     }
260 }
261 
JsOnDisAppear(const JSCallbackInfo & info)262 void JSInteractableView::JsOnDisAppear(const JSCallbackInfo& info)
263 {
264     if (info[0]->IsUndefined() && IsDisableEventVersion()) {
265         ViewAbstractModel::GetInstance()->DisableOnDisAppear();
266         return;
267     }
268     if (info[0]->IsFunction()) {
269         RefPtr<JsFunction> jsOnDisAppearFunc =
270             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
271         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
272         auto onDisappear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc),
273                                node = frameNode]() {
274             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
275             ACE_SCORING_EVENT("onDisAppear");
276             PipelineContext::SetCallBackNode(node);
277             func->Execute();
278         };
279         ViewAbstractModel::GetInstance()->SetOnDisAppear(std::move(onDisappear));
280     }
281 }
282 
JsOnAttach(const JSCallbackInfo & info)283 void JSInteractableView::JsOnAttach(const JSCallbackInfo& info)
284 {
285     if (info[0]->IsUndefined() && IsDisableEventVersion()) {
286         ViewAbstractModel::GetInstance()->DisableOnAttach();
287         return;
288     }
289     if (info[0]->IsFunction()) {
290         RefPtr<JsFunction> jsOnAttachFunc =
291             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
292         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
293         auto onAttach = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAttachFunc), node = frameNode]() {
294             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
295             ACE_SCORING_EVENT("onAttach");
296             PipelineContext::SetCallBackNode(node);
297             func->Execute();
298         };
299         ViewAbstractModel::GetInstance()->SetOnAttach(std::move(onAttach));
300     }
301 }
302 
JsOnDetach(const JSCallbackInfo & info)303 void JSInteractableView::JsOnDetach(const JSCallbackInfo& info)
304 {
305     if (info[0]->IsUndefined() && IsDisableEventVersion()) {
306         ViewAbstractModel::GetInstance()->DisableOnDetach();
307         return;
308     }
309     if (info[0]->IsFunction()) {
310         RefPtr<JsFunction> jsOnDetachFunc =
311             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
312         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
313         auto onDetach = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDetachFunc), node = frameNode]() {
314             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
315             ACE_SCORING_EVENT("onDetach");
316             PipelineContext::SetCallBackNode(node);
317             func->Execute();
318         };
319         ViewAbstractModel::GetInstance()->SetOnDetach(std::move(onDetach));
320     }
321 }
322 
JsOnAccessibility(const JSCallbackInfo & info)323 void JSInteractableView::JsOnAccessibility(const JSCallbackInfo& info)
324 {
325     if (!info[0]->IsFunction()) {
326         return;
327     }
328     RefPtr<JsFunction> jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
329     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
330     auto onAccessibility = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = frameNode](
331                                const std::string& param) {
332         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
333         ACE_SCORING_EVENT("onAccessibility");
334         PipelineContext::SetCallBackNode(node);
335 
336         func->Execute({ "eventType" }, param);
337     };
338     ViewAbstractModel::GetInstance()->SetOnAccessibility(std::move(onAccessibility));
339 }
340 
JsCommonRemoteMessage(const JSCallbackInfo & info)341 void JSInteractableView::JsCommonRemoteMessage(const JSCallbackInfo& info)
342 {
343     if (info.Length() != 0 && info[0]->IsObject()) {
344         RemoteCallback remoteCallback;
345         JsRemoteMessage(info, remoteCallback);
346         ViewAbstractModel::GetInstance()->SetOnRemoteMessage(std::move(remoteCallback));
347     }
348 }
349 
JsRemoteMessage(const JSCallbackInfo & info,RemoteCallback & remoteCallback)350 void JSInteractableView::JsRemoteMessage(const JSCallbackInfo& info, RemoteCallback& remoteCallback)
351 {
352     if (!info[0]->IsObject()) {
353         return;
354     }
355 
356     auto eventCallback = GetRemoteMessageEventCallback(info);
357     remoteCallback = [func = std::move(eventCallback)](const BaseEventInfo* info) {
358         auto touchInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
359         if (touchInfo && touchInfo->GetType().compare("onClick") == 0) {
360             func();
361         }
362     };
363 }
364 
GetRemoteMessageEventCallback(const JSCallbackInfo & info)365 std::function<void()> JSInteractableView::GetRemoteMessageEventCallback(const JSCallbackInfo& info)
366 {
367     JSRef<JSVal> arg = info[0];
368     if (!arg->IsObject()) {
369         return []() {};
370     }
371     auto obj = JSRef<JSObject>::Cast(arg);
372     auto actionValue = obj->GetProperty("action");
373     std::string action;
374     if (actionValue->IsString()) {
375         action = actionValue->ToString();
376     }
377     auto abilityValue = obj->GetProperty("ability");
378     std::string ability;
379     if (abilityValue->IsString()) {
380         ability = abilityValue->ToString();
381     }
382     auto paramsObj = obj->GetProperty("params");
383     std::string params;
384     if (paramsObj->IsObject()) {
385         params = paramsObj->ToString();
386     }
387     auto eventCallback = [action, ability, params]() {
388         if (action.compare("message") == 0) {
389             // onCall
390         } else if (action.compare("route") == 0) {
391             // startAbility
392 #ifdef PLUGIN_COMPONENT_SUPPORTED
393             std::vector<std::string> strList;
394             SplitString(ability, '/', strList);
395             if (strList.size() <= 1) {
396                 return;
397             }
398             int32_t result = PluginManager::GetInstance().StartAbility(strList[0], strList[1], params);
399             if (result != 0) {
400                 LOGW("Failed to start the APP %{public}s.", ability.c_str());
401             }
402 #else
403             LOGW("Unsupported Windows and Mac platforms to start APP.");
404 #endif
405         }
406     };
407 
408     return eventCallback;
409 }
410 
411 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
ReportClickEvent(const WeakPtr<NG::FrameNode> & node,const std::string text)412 void JSInteractableView::ReportClickEvent(const WeakPtr<NG::FrameNode>& node, const std::string text)
413 {
414     if (UiSessionManager::GetInstance().GetClickEventRegistered()) {
415         auto data = JsonUtil::Create();
416         data->Put("event", "onClick");
417         std::string content = text;
418         if (!node.Invalid()) {
419             data->Put("id", node.GetRawPtr()->GetId());
420             auto children = node.GetRawPtr()->GetChildren();
421             if (!children.empty()) {
422                 node.GetRawPtr()->GetContainerComponentText(content);
423             }
424             data->Put("text", content.data());
425             data->Put("position", node.GetRawPtr()->GetGeometryNode()->GetFrameRect().ToString().data());
426         }
427         UiSessionManager::GetInstance().ReportClickEvent(data->ToString());
428     }
429 }
430 #endif
431 
SplitString(const std::string & str,char tag,std::vector<std::string> & strList)432 void JSInteractableView::SplitString(const std::string& str, char tag, std::vector<std::string>& strList)
433 {
434     std::string subStr;
435     for (size_t i = 0; i < str.length(); i++) {
436         if (tag == str[i]) {
437             if (!subStr.empty()) {
438                 strList.push_back(subStr);
439                 subStr.clear();
440             }
441         } else {
442             subStr.push_back(str[i]);
443         }
444     }
445     if (!subStr.empty()) {
446         strList.push_back(subStr);
447     }
448 }
449 } // namespace OHOS::Ace::Framework
450