1 /*
2 * Copyright (c) 2021 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/log_wrapper.h"
19 #include "core/common/container.h"
20 #ifdef PLUGIN_COMPONENT_SUPPORTED
21 #include "core/common/plugin_manager.h"
22 #endif
23 #include "core/components/gesture_listener/gesture_listener_component.h"
24 #include "core/gestures/click_recognizer.h"
25 #include "core/pipeline/base/single_child.h"
26 #include "frameworks/bridge/declarative_frontend/engine/functions/js_click_function.h"
27 #include "frameworks/bridge/declarative_frontend/engine/functions/js_hover_function.h"
28 #include "frameworks/bridge/declarative_frontend/engine/functions/js_key_function.h"
29 #include "frameworks/bridge/declarative_frontend/engine/js_execution_scope_defines.h"
30 #include "frameworks/bridge/declarative_frontend/jsview/js_pan_handler.h"
31 #include "frameworks/bridge/declarative_frontend/jsview/js_touch_handler.h"
32 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
33
34 namespace OHOS::Ace::Framework {
35
JsOnTouch(const JSCallbackInfo & args)36 void JSInteractableView::JsOnTouch(const JSCallbackInfo& args)
37 {
38 LOGD("JSInteractableView JsOnTouch");
39 if (args[0]->IsFunction()) {
40 auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
41 if (!inspector) {
42 LOGE("fail to get inspector for on touch event");
43 return;
44 }
45 auto impl = inspector->GetInspectorFunctionImpl();
46 RefPtr<JsTouchFunction> jsOnTouchFunc = AceType::MakeRefPtr<JsTouchFunction>(JSRef<JSFunc>::Cast(args[0]));
47 auto onTouchId = EventMarker(
48 [execCtx = args.GetExecutionContext(), func = std::move(jsOnTouchFunc), impl](BaseEventInfo* info) {
49 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
50 if (impl) {
51 impl->UpdateEventInfo(*info);
52 }
53 auto touchInfo = TypeInfoHelper::DynamicCast<TouchEventInfo>(info);
54 ACE_SCORING_EVENT("onTouch");
55 func->Execute(*touchInfo);
56 },
57 "onTouch");
58 auto touchComponent = ViewStackProcessor::GetInstance()->GetTouchListenerComponent();
59 touchComponent->SetOnTouchId(onTouchId);
60 }
61 }
62
JsOnKey(const JSCallbackInfo & args)63 void JSInteractableView::JsOnKey(const JSCallbackInfo& args)
64 {
65 if (args[0]->IsFunction()) {
66 RefPtr<JsKeyFunction> jsOnKeyFunc = AceType::MakeRefPtr<JsKeyFunction>(JSRef<JSFunc>::Cast(args[0]));
67 auto onKeyId = EventMarker(
68 [execCtx = args.GetExecutionContext(), func = std::move(jsOnKeyFunc)](BaseEventInfo* info) {
69 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
70 auto keyInfo = TypeInfoHelper::DynamicCast<KeyEventInfo>(info);
71 ACE_SCORING_EVENT("onKey");
72 func->Execute(*keyInfo);
73 },
74 "onKey", 0);
75 auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent();
76 focusableComponent->SetFocusable(true);
77 focusableComponent->SetOnKeyId(onKeyId);
78 }
79 }
80
JsOnHover(const JSCallbackInfo & args)81 void JSInteractableView::JsOnHover(const JSCallbackInfo& args)
82 {
83 if (args[0]->IsFunction()) {
84 RefPtr<JsHoverFunction> jsOnHoverFunc = AceType::MakeRefPtr<JsHoverFunction>(JSRef<JSFunc>::Cast(args[0]));
85 auto onHoverId = [execCtx = args.GetExecutionContext(), func = std::move(jsOnHoverFunc)](bool info) {
86 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
87 ACE_SCORING_EVENT("onHover");
88 func->Execute(info);
89 };
90 auto box = ViewStackProcessor::GetInstance()->GetBoxComponent();
91 box->SetOnHoverId(onHoverId);
92 }
93 }
94
JsOnPan(const JSCallbackInfo & args)95 void JSInteractableView::JsOnPan(const JSCallbackInfo& args)
96 {
97 LOGD("JSInteractableView JsOnPan");
98 if (args[0]->IsObject()) {
99 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
100 JSPanHandler* handler = obj->Unwrap<JSPanHandler>();
101 if (handler) {
102 handler->CreateComponent(args);
103 }
104 }
105 }
106
JsOnDelete(const JSCallbackInfo & info)107 void JSInteractableView::JsOnDelete(const JSCallbackInfo& info)
108 {
109 LOGD("JSInteractableView JsOnDelete");
110 if (info[0]->IsFunction()) {
111 RefPtr<JsFunction> jsOnDeleteFunc =
112 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
113 auto onDeleteId = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsOnDeleteFunc)]() {
114 LOGD("onDelete callback");
115 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
116 ACE_SCORING_EVENT("onDelete");
117 func->Execute();
118 });
119 auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent();
120 focusableComponent->SetOnDeleteId(onDeleteId);
121 }
122 }
123
JsTouchable(const JSCallbackInfo & info)124 void JSInteractableView::JsTouchable(const JSCallbackInfo& info)
125 {
126 if (info[0]->IsBoolean()) {
127 auto mainComponent = ViewStackProcessor::GetInstance()->GetMainComponent();
128 if (!mainComponent) {
129 return;
130 }
131 mainComponent->SetTouchable(info[0]->ToBoolean());
132 }
133 }
134
JsOnClick(const JSCallbackInfo & info)135 void JSInteractableView::JsOnClick(const JSCallbackInfo& info)
136 {
137 if (info[0]->IsFunction()) {
138 auto click = ViewStackProcessor::GetInstance()->GetBoxComponent();
139 auto tapGesture = GetTapGesture(info);
140 if (tapGesture) {
141 click->SetOnClick(tapGesture);
142 }
143
144 auto onClickId = GetClickEventMarker(info);
145 auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent();
146 focusableComponent->SetOnClickId(onClickId);
147 }
148 }
149
GetClickEventMarker(const JSCallbackInfo & info)150 EventMarker JSInteractableView::GetClickEventMarker(const JSCallbackInfo& info)
151 {
152 auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
153 if (!inspector) {
154 LOGE("fail to get inspector for on get click event marker");
155 return EventMarker();
156 }
157 auto impl = inspector->GetInspectorFunctionImpl();
158 RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
159 auto onClickId = EventMarker(
160 [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl](const BaseEventInfo* info) {
161 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
162 auto clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
163 auto newInfo = *clickInfo;
164 if (impl) {
165 impl->UpdateEventInfo(newInfo);
166 }
167 ACE_SCORING_EVENT("onClick");
168 func->Execute(newInfo);
169 });
170 return onClickId;
171 }
172
GetTapGesture(const JSCallbackInfo & info,int32_t countNum,int32_t fingerNum)173 RefPtr<Gesture> JSInteractableView::GetTapGesture(
174 const JSCallbackInfo& info, int32_t countNum, int32_t fingerNum)
175 {
176 auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
177 if (!inspector) {
178 LOGE("fail to get inspector for on touch event");
179 return nullptr;
180 }
181 auto impl = inspector->GetInspectorFunctionImpl();
182 RefPtr<Gesture> tapGesture = AceType::MakeRefPtr<TapGesture>(countNum, fingerNum);
183 RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
184 tapGesture->SetOnActionId(
185 [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl](GestureEvent& info) {
186 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
187 if (impl) {
188 impl->UpdateEventInfo(info);
189 }
190 ACE_SCORING_EVENT("onClick");
191 func->Execute(info);
192 });
193 return tapGesture;
194 }
195
GetRemoteMessageTapGesture(const JSCallbackInfo & info)196 RefPtr<Gesture> JSInteractableView::GetRemoteMessageTapGesture(const JSCallbackInfo& info)
197 {
198 RefPtr<Gesture> tapGesture = AceType::MakeRefPtr<TapGesture>();
199 RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
200 auto eventCallback = GetRemoteMessageEventCallback(info);
201 tapGesture->SetOnActionId([func = std::move(eventCallback)]
202 (const GestureEvent& info) {
203 func();
204 });
205 return tapGesture;
206 }
207
SetFocusable(bool focusable)208 void JSInteractableView::SetFocusable(bool focusable)
209 {
210 auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent();
211 if (focusableComponent) {
212 focusableComponent->SetFocusable(focusable);
213 }
214 }
SetFocusNode(bool isFocusNode)215 void JSInteractableView::SetFocusNode(bool isFocusNode)
216 {
217 auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent(false);
218 if (focusableComponent) {
219 focusableComponent->SetFocusNode(!isFocusNode);
220 }
221 }
222
JsOnAppear(const JSCallbackInfo & info)223 void JSInteractableView::JsOnAppear(const JSCallbackInfo& info)
224 {
225 if (info[0]->IsFunction()) {
226 RefPtr<JsFunction> jsOnAppearFunc =
227 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
228
229 auto onAppearId = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc)]() {
230 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
231 LOGI("About to call JsOnAppear method on js");
232 ACE_SCORING_EVENT("onAppear");
233 func->Execute();
234 });
235 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
236 component->SetOnAppearEventId(onAppearId);
237 }
238 }
239
JsOnDisAppear(const JSCallbackInfo & info)240 void JSInteractableView::JsOnDisAppear(const JSCallbackInfo& info)
241 {
242 if (info[0]->IsFunction()) {
243 RefPtr<JsFunction> jsOnDisAppearFunc =
244 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
245 auto onDisAppearId = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc)]() {
246 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
247 LOGD("Start to call JsOnDisAppear method on js");
248 ACE_SCORING_EVENT("onDisAppear");
249 func->Execute();
250 });
251 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
252 component->SetOnDisappearEventId(onDisAppearId);
253 }
254 }
255
JsOnAccessibility(const JSCallbackInfo & info)256 void JSInteractableView::JsOnAccessibility(const JSCallbackInfo& info)
257 {
258 auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
259 if (!inspector) {
260 LOGE("this component does not hava inspetor");
261 return;
262 }
263 inspector->SetAccessibilityEvent(GetEventMarker(info, { "eventType" }));
264 }
265
UpdateEventTarget(NodeId id,BaseEventInfo & info)266 void JSInteractableView::UpdateEventTarget(NodeId id, BaseEventInfo& info)
267 {
268 auto container = Container::Current();
269 if (!container) {
270 LOGE("fail to get container");
271 return;
272 }
273 auto context = container->GetPipelineContext();
274 if (!context) {
275 LOGE("fail to get context");
276 return;
277 }
278 auto accessibilityManager = context->GetAccessibilityManager();
279 if (!accessibilityManager) {
280 LOGE("fail to get accessibility manager");
281 return;
282 }
283 accessibilityManager->UpdateEventTarget(id, info);
284 }
285
GetEventMarker(const JSCallbackInfo & info,const std::vector<std::string> & keys)286 EventMarker JSInteractableView::GetEventMarker(const JSCallbackInfo& info, const std::vector<std::string>& keys)
287 {
288 if (!info[0]->IsFunction()) {
289 LOGE("info[0] is not a function.");
290 return EventMarker();
291 }
292
293 RefPtr<JsFunction> jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
294 auto eventMarker =
295 EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc), keys](const std::string& param) {
296 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
297 ACE_SCORING_EVENT("onClick");
298 func->Execute(keys, param);
299 });
300 return eventMarker;
301 }
302
JsCommonRemoteMessage(const JSCallbackInfo & info)303 void JSInteractableView::JsCommonRemoteMessage(const JSCallbackInfo& info)
304 {
305 if (info.Length() != 0 && info[0]->IsObject()) {
306 auto box = ViewStackProcessor::GetInstance()->GetBoxComponent();
307 EventMarker remoteMessageEventId;
308 JsRemoteMessage(info, remoteMessageEventId);
309 box->SetRemoteMessageEvent(remoteMessageEventId);
310 }
311 }
312
JsRemoteMessage(const JSCallbackInfo & info,EventMarker & eventMarker)313 void JSInteractableView::JsRemoteMessage(const JSCallbackInfo& info, EventMarker& eventMarker)
314 {
315 if (info.Length() == 0 || !info[0]->IsObject()) {
316 LOGE("RemoteMessage JSCallbackInfo param is empty or type is not Object.");
317 return;
318 }
319
320 auto eventCallback = GetRemoteMessageEventCallback(info);
321 eventMarker = EventMarker(
322 [func = std::move(eventCallback)](BaseEventInfo* info) {
323 auto touchInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
324 if (touchInfo && touchInfo->GetType().compare("onClick") == 0) {
325 func();
326 }
327 });
328 }
329
GetRemoteMessageEventCallback(const JSCallbackInfo & info)330 std::function<void()> JSInteractableView::GetRemoteMessageEventCallback(const JSCallbackInfo& info)
331 {
332 auto obj = JSRef<JSObject>::Cast(info[0]);
333 auto actionValue = obj->GetProperty("action");
334 std::string action;
335 if (actionValue->IsString()) {
336 action = actionValue->ToString();
337 }
338 auto abilityValue = obj->GetProperty("ability");
339 std::string ability;
340 if (abilityValue->IsString()) {
341 ability = abilityValue->ToString();
342 }
343 auto paramsObj = obj->GetProperty("params");
344 std::string params;
345 if (paramsObj->IsObject()) {
346 params = paramsObj->ToString();
347 }
348 auto eventCallback = [action, ability, params]() {
349 LOGE("JSInteractableView::JsRemoteMessage. eventMarker");
350 if (action.compare("message") == 0) {
351 // onCall
352 } else if (action.compare("route") == 0) {
353 // startAbility
354 #ifdef PLUGIN_COMPONENT_SUPPORTED
355 std::vector<std::string> strList;
356 SplitString(ability, '/', strList);
357 if (strList.size() <= 1) {
358 LOGE("App bundleName or abilityName is empty.");
359 return;
360 }
361 int32_t result = PluginManager::GetInstance().StartAbility(strList[0], strList[1], params);
362 if (result != 0) {
363 LOGE("JSInteractableView::JsRemoteMessage: Failed to start the APP %{public}s.", ability.c_str());
364 }
365 #else
366 LOGE("JSInteractableView::JsRemoteMessage: Unsupport Windows and Mac platforms to start APP.");
367 #endif
368 } else {
369 LOGE("action's name is not message or route.");
370 }
371 };
372
373 return eventCallback;
374 }
375
SplitString(const std::string & str,char tag,std::vector<std::string> & strList)376 void JSInteractableView::SplitString(const std::string& str, char tag, std::vector<std::string>& strList)
377 {
378 std::string subStr;
379 for (size_t i = 0; i < str.length(); i++) {
380 if (tag == str[i]) {
381 if (!subStr.empty()) {
382 strList.push_back(subStr);
383 subStr.clear();
384 }
385 } else {
386 subStr.push_back(str[i]);
387 }
388 }
389 if (!subStr.empty()) {
390 strList.push_back(subStr);
391 }
392 }
393 } // namespace OHOS::Ace::Framework
394