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