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