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