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
18 #include "base/log/ace_scoring_log.h"
19 #include "base/log/log_wrapper.h"
20 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
21 #include "bridge/declarative_frontend/engine/functions/js_hover_function.h"
22 #include "bridge/declarative_frontend/engine/functions/js_key_function.h"
23 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
24 #include "bridge/declarative_frontend/jsview/js_pan_handler.h"
25 #include "bridge/declarative_frontend/jsview/js_touch_handler.h"
26 #include "bridge/declarative_frontend/jsview/js_utils.h"
27 #include "bridge/declarative_frontend/view_stack_processor.h"
28 #include "core/common/container.h"
29 #include "core/components/gesture_listener/gesture_listener_component.h"
30 #include "core/components_ng/base/view_abstract_model.h"
31 #include "core/components_ng/base/view_stack_processor.h"
32 #include "core/gestures/click_recognizer.h"
33 #include "core/pipeline/base/single_child.h"
34 #include "core/pipeline/pipeline_context.h"
35
36 #ifdef PLUGIN_COMPONENT_SUPPORTED
37 #include "core/common/plugin_manager.h"
38 #endif
39
40 namespace OHOS::Ace::Framework {
41
JsOnTouch(const JSCallbackInfo & args)42 void JSInteractableView::JsOnTouch(const JSCallbackInfo& args)
43 {
44 if (args[0]->IsUndefined() && IsDisableEventVersion()) {
45 ViewAbstractModel::GetInstance()->DisableOnTouch();
46 return;
47 }
48 if (!args[0]->IsFunction()) {
49 return;
50 }
51 RefPtr<JsTouchFunction> jsOnTouchFunc = AceType::MakeRefPtr<JsTouchFunction>(JSRef<JSFunc>::Cast(args[0]));
52 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
53 auto onTouch = [execCtx = args.GetExecutionContext(), func = std::move(jsOnTouchFunc), node = frameNode](
54 TouchEventInfo& info) {
55 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
56 ACE_SCORING_EVENT("onTouch");
57 PipelineContext::SetCallBackNode(node);
58 func->Execute(info);
59 };
60 ViewAbstractModel::GetInstance()->SetOnTouch(std::move(onTouch));
61 }
62
JsOnKey(const JSCallbackInfo & args)63 void JSInteractableView::JsOnKey(const JSCallbackInfo& args)
64 {
65 if (args[0]->IsUndefined() && IsDisableEventVersion()) {
66 ViewAbstractModel::GetInstance()->DisableOnKeyEvent();
67 return;
68 }
69 if (!args[0]->IsFunction()) {
70 return;
71 }
72 RefPtr<JsKeyFunction> JsOnKeyEvent = AceType::MakeRefPtr<JsKeyFunction>(JSRef<JSFunc>::Cast(args[0]));
73 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
74 auto onKeyEvent = [execCtx = args.GetExecutionContext(), func = std::move(JsOnKeyEvent), node = frameNode](
75 KeyEventInfo& info) {
76 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
77 ACE_SCORING_EVENT("onKey");
78 PipelineContext::SetCallBackNode(node);
79 func->Execute(info);
80 };
81 ViewAbstractModel::GetInstance()->SetOnKeyEvent(std::move(onKeyEvent));
82 }
83
JsOnHover(const JSCallbackInfo & info)84 void JSInteractableView::JsOnHover(const JSCallbackInfo& info)
85 {
86 if (info[0]->IsUndefined() && IsDisableEventVersion()) {
87 ViewAbstractModel::GetInstance()->DisableOnHover();
88 return;
89 }
90 if (!info[0]->IsFunction()) {
91 return;
92 }
93 RefPtr<JsHoverFunction> jsOnHoverFunc = AceType::MakeRefPtr<JsHoverFunction>(JSRef<JSFunc>::Cast(info[0]));
94 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
95 auto onHover = [execCtx = info.GetExecutionContext(), func = std::move(jsOnHoverFunc), node = frameNode](
96 bool isHover, HoverInfo& hoverInfo) {
97 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
98 ACE_SCORING_EVENT("onHover");
99 PipelineContext::SetCallBackNode(node);
100 func->HoverExecute(isHover, hoverInfo);
101 };
102 ViewAbstractModel::GetInstance()->SetOnHover(std::move(onHover));
103 }
104
JsOnPan(const JSCallbackInfo & args)105 void JSInteractableView::JsOnPan(const JSCallbackInfo& args)
106 {
107 if (args[0]->IsObject()) {
108 // TODO: JSPanHandler should support ng build
109 #ifndef NG_BUILD
110 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
111 JSPanHandler* handler = obj->Unwrap<JSPanHandler>();
112 if (handler) {
113 handler->CreateComponent(args);
114 }
115 #endif
116 }
117 }
118
JsOnDelete(const JSCallbackInfo & info)119 void JSInteractableView::JsOnDelete(const JSCallbackInfo& info)
120 {
121 if (info[0]->IsFunction()) {
122 RefPtr<JsFunction> jsOnDeleteFunc =
123 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
124 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
125 auto onDelete = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDeleteFunc), node = frameNode]() {
126 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
127 ACE_SCORING_EVENT("onDelete");
128 PipelineContext::SetCallBackNode(node);
129 func->Execute();
130 };
131 ViewAbstractModel::GetInstance()->SetOnDelete(std::move(onDelete));
132 }
133 }
134
JsTouchable(const JSCallbackInfo & info)135 void JSInteractableView::JsTouchable(const JSCallbackInfo& info)
136 {
137 if (info[0]->IsBoolean()) {
138 ViewAbstractModel::GetInstance()->SetTouchable(info[0]->ToBoolean());
139 }
140 }
141
JsMonopolizeEvents(const JSCallbackInfo & info)142 void JSInteractableView::JsMonopolizeEvents(const JSCallbackInfo& info)
143 {
144 if (info[0]->IsBoolean()) {
145 ViewAbstractModel::GetInstance()->SetMonopolizeEvents(info[0]->ToBoolean());
146 } else {
147 ViewAbstractModel::GetInstance()->SetMonopolizeEvents(false);
148 }
149 }
150
JsOnClick(const JSCallbackInfo & info)151 void JSInteractableView::JsOnClick(const JSCallbackInfo& info)
152 {
153 JSRef<JSVal> jsOnClickVal = info[0];
154 if (jsOnClickVal->IsUndefined() && IsDisableEventVersion()) {
155 ViewAbstractModel::GetInstance()->DisableOnClick();
156 return;
157 }
158 if (!jsOnClickVal->IsFunction()) {
159 return;
160 }
161 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
162 auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
163 auto onTap = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = frameNode](GestureEvent& info) {
164 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
165 ACE_SCORING_EVENT("onClick");
166 PipelineContext::SetCallBackNode(node);
167 func->Execute(info);
168 };
169 auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = frameNode](
170 const ClickInfo* info) {
171 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
172 ACE_SCORING_EVENT("onClick");
173 PipelineContext::SetCallBackNode(node);
174 func->Execute(*info);
175 };
176
177 ViewAbstractModel::GetInstance()->SetOnClick(std::move(onTap), std::move(onClick));
178 auto focusHub = NG::ViewStackProcessor::GetInstance()->GetOrCreateMainFrameNodeFocusHub();
179 CHECK_NULL_VOID(focusHub);
180 focusHub->SetFocusable(true, false);
181 }
182
SetFocusable(bool focusable)183 void JSInteractableView::SetFocusable(bool focusable)
184 {
185 ViewAbstractModel::GetInstance()->SetFocusable(focusable);
186 }
187
SetFocusNode(bool isFocusNode)188 void JSInteractableView::SetFocusNode(bool isFocusNode)
189 {
190 ViewAbstractModel::GetInstance()->SetFocusNode(isFocusNode);
191 }
192
JsOnAppear(const JSCallbackInfo & info)193 void JSInteractableView::JsOnAppear(const JSCallbackInfo& info)
194 {
195 if (info[0]->IsUndefined() && IsDisableEventVersion()) {
196 ViewAbstractModel::GetInstance()->DisableOnAppear();
197 return;
198 }
199 if (info[0]->IsFunction()) {
200 RefPtr<JsFunction> jsOnAppearFunc =
201 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
202 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
203 auto onAppear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc), node = frameNode]() {
204 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
205 ACE_SCORING_EVENT("onAppear");
206 PipelineContext::SetCallBackNode(node);
207 func->Execute();
208 };
209 ViewAbstractModel::GetInstance()->SetOnAppear(std::move(onAppear));
210 }
211 }
212
JsOnDisAppear(const JSCallbackInfo & info)213 void JSInteractableView::JsOnDisAppear(const JSCallbackInfo& info)
214 {
215 if (info[0]->IsUndefined() && IsDisableEventVersion()) {
216 ViewAbstractModel::GetInstance()->DisableOnDisAppear();
217 return;
218 }
219 if (info[0]->IsFunction()) {
220 RefPtr<JsFunction> jsOnDisAppearFunc =
221 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
222 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
223 auto onDisappear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc),
224 node = frameNode]() {
225 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
226 ACE_SCORING_EVENT("onDisAppear");
227 PipelineContext::SetCallBackNode(node);
228 func->Execute();
229 };
230 ViewAbstractModel::GetInstance()->SetOnDisAppear(std::move(onDisappear));
231 }
232 }
233
JsOnAccessibility(const JSCallbackInfo & info)234 void JSInteractableView::JsOnAccessibility(const JSCallbackInfo& info)
235 {
236 if (!info[0]->IsFunction()) {
237 return;
238 }
239 RefPtr<JsFunction> jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
240 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
241 auto onAccessibility = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = frameNode](
242 const std::string& param) {
243 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
244 ACE_SCORING_EVENT("onAccessibility");
245 PipelineContext::SetCallBackNode(node);
246
247 func->Execute({ "eventType" }, param);
248 };
249 ViewAbstractModel::GetInstance()->SetOnAccessibility(std::move(onAccessibility));
250 }
251
JsCommonRemoteMessage(const JSCallbackInfo & info)252 void JSInteractableView::JsCommonRemoteMessage(const JSCallbackInfo& info)
253 {
254 if (info.Length() != 0 && info[0]->IsObject()) {
255 RemoteCallback remoteCallback;
256 JsRemoteMessage(info, remoteCallback);
257 ViewAbstractModel::GetInstance()->SetOnRemoteMessage(std::move(remoteCallback));
258 }
259 }
260
JsRemoteMessage(const JSCallbackInfo & info,RemoteCallback & remoteCallback)261 void JSInteractableView::JsRemoteMessage(const JSCallbackInfo& info, RemoteCallback& remoteCallback)
262 {
263 if (!info[0]->IsObject()) {
264 return;
265 }
266
267 auto eventCallback = GetRemoteMessageEventCallback(info);
268 remoteCallback = [func = std::move(eventCallback)](const BaseEventInfo* info) {
269 auto touchInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
270 if (touchInfo && touchInfo->GetType().compare("onClick") == 0) {
271 func();
272 }
273 };
274 }
275
GetRemoteMessageEventCallback(const JSCallbackInfo & info)276 std::function<void()> JSInteractableView::GetRemoteMessageEventCallback(const JSCallbackInfo& info)
277 {
278 auto obj = JSRef<JSObject>::Cast(info[0]);
279 auto actionValue = obj->GetProperty("action");
280 std::string action;
281 if (actionValue->IsString()) {
282 action = actionValue->ToString();
283 }
284 auto abilityValue = obj->GetProperty("ability");
285 std::string ability;
286 if (abilityValue->IsString()) {
287 ability = abilityValue->ToString();
288 }
289 auto paramsObj = obj->GetProperty("params");
290 std::string params;
291 if (paramsObj->IsObject()) {
292 params = paramsObj->ToString();
293 }
294 auto eventCallback = [action, ability, params]() {
295 if (action.compare("message") == 0) {
296 // onCall
297 } else if (action.compare("route") == 0) {
298 // startAbility
299 #ifdef PLUGIN_COMPONENT_SUPPORTED
300 std::vector<std::string> strList;
301 SplitString(ability, '/', strList);
302 if (strList.size() <= 1) {
303 return;
304 }
305 int32_t result = PluginManager::GetInstance().StartAbility(strList[0], strList[1], params);
306 if (result != 0) {
307 LOGW("Failed to start the APP %{public}s.", ability.c_str());
308 }
309 #else
310 LOGW("Unsupported Windows and Mac platforms to start APP.");
311 #endif
312 }
313 };
314
315 return eventCallback;
316 }
317
SplitString(const std::string & str,char tag,std::vector<std::string> & strList)318 void JSInteractableView::SplitString(const std::string& str, char tag, std::vector<std::string>& strList)
319 {
320 std::string subStr;
321 for (size_t i = 0; i < str.length(); i++) {
322 if (tag == str[i]) {
323 if (!subStr.empty()) {
324 strList.push_back(subStr);
325 subStr.clear();
326 }
327 } else {
328 subStr.push_back(str[i]);
329 }
330 }
331 if (!subStr.empty()) {
332 strList.push_back(subStr);
333 }
334 }
335 } // namespace OHOS::Ace::Framework
336