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 "core/components/form/form_element.h"
17 
18 #include "core/common/container_scope.h"
19 #include "core/common/form_manager.h"
20 #ifdef OHOS_STANDARD_SYSTEM
21 #include "form_info.h"
22 #endif
23 #include "frameworks/base/utils/string_utils.h"
24 #include "frameworks/core/components/form/form_component.h"
25 #include "frameworks/core/components/form/render_form.h"
26 #include "frameworks/core/components/form/resource/form_manager_delegate.h"
27 
28 namespace OHOS::Ace {
29 
~FormElement()30 FormElement::~FormElement()
31 {
32     formManagerBridge_.Reset();
33 
34     auto id = subContainer_->GetRunningCardId();
35     FormManager::GetInstance().RemoveSubContainer(id);
36 
37     subContainer_->Destroy();
38     subContainer_.Reset();
39 }
40 
Update()41 void FormElement::Update()
42 {
43     auto form = AceType::DynamicCast<FormComponent>(component_);
44     if (!form) {
45         LOGE("could not get form component for update");
46         return;
47     }
48     SetElementId(form->GetElementId());
49 
50     auto info = form->GetFormRequestInfo();
51     if (info.bundleName != cardInfo_.bundleName || info.abilityName != cardInfo_.abilityName ||
52         info.moduleName != cardInfo_.moduleName || info.cardName != cardInfo_.cardName ||
53         info.dimension != cardInfo_.dimension) {
54         cardInfo_ = info;
55     } else {
56         // for update form component
57         UpdateInner(info);
58         return;
59     }
60 
61     GetRenderNode()->Update(component_);
62 
63 #if OHOS_STANDARD_SYSTEM
64     AppExecFwk::FormInfo formInfo;
65     if (!FormManagerDelegate::GetFormInfo(info.bundleName, info.moduleName, info.cardName, formInfo)) {
66         LOGE("failed to get formInfo with bundleName: %{public}s, moduleName: %{public}s, cardName: %{public}s",
67             info.bundleName.c_str(), info.moduleName.c_str(), info.cardName.c_str());
68     }
69 #endif
70 
71     CreateCardContainer();
72 
73     if (formManagerBridge_) {
74 #if OHOS_STANDARD_SYSTEM
75         formManagerBridge_->AddForm(GetContext(), info, formInfo);
76 #else
77         formManagerBridge_->AddForm(GetContext(), info);
78 #endif
79     }
80 
81     InitEvent(form);
82 }
83 
PerformBuild()84 void FormElement::PerformBuild()
85 {
86     subContainer_->SetFormElement(AceType::WeakClaim(this));
87 }
88 
InitEvent(const RefPtr<FormComponent> & component)89 void FormElement::InitEvent(const RefPtr<FormComponent>& component)
90 {
91     if (!component->GetOnAcquireFormEventId().IsEmpty()) {
92         onAcquireEvent_ =
93             AceAsyncEvent<void(const std::string&)>::Create(component->GetOnAcquireFormEventId(), context_);
94     }
95 
96     if (!component->GetOnErrorEvent().IsEmpty()) {
97         onErrorEvent_ = AceAsyncEvent<void(const std::string&)>::Create(component->GetOnErrorEvent(), context_);
98     }
99 
100     if (!component->GetOnUninstallEvent().IsEmpty()) {
101         onUninstallEvent_ =
102             AceAsyncEvent<void(const std::string&)>::Create(component->GetOnUninstallEvent(), context_);
103     }
104 
105     if (!component->GetOnRouterEvent().IsEmpty()) {
106         onRouterEvent_ = AceAsyncEvent<void(const std::string&)>::Create(component->GetOnRouterEvent(), context_);
107     }
108 }
109 
UpdateInner(const RequestFormInfo & info)110 void FormElement::UpdateInner(const RequestFormInfo& info)
111 {
112     if (cardInfo_.allowUpdate != info.allowUpdate) {
113         cardInfo_.allowUpdate = info.allowUpdate;
114         LOGI(" update card allow info:%{public}d", cardInfo_.allowUpdate);
115         if (subContainer_) {
116             subContainer_->SetAllowUpdate(cardInfo_.allowUpdate);
117         }
118     }
119 
120     if (cardInfo_.width != info.width || cardInfo_.height != info.height) {
121         LOGI("update card size old w:%lf,h:%lf", cardInfo_.width.Value(), cardInfo_.height.Value());
122         LOGI("update card size new w:%lf,h:%lf", info.width.Value(), info.height.Value());
123         cardInfo_.width = info.width;
124         cardInfo_.height = info.height;
125         GetRenderNode()->Update(component_);
126         subContainer_->SetFormComponent(component_);
127         subContainer_->UpdateRootElementSize();
128         subContainer_->UpdateSurfaceSize();
129     }
130 }
131 
HandleOnAcquireEvent(int64_t id)132 void FormElement::HandleOnAcquireEvent(int64_t id)
133 {
134     if (!onAcquireEvent_) {
135         LOGE("could not find available event handle");
136         return;
137     }
138     auto context = context_.Upgrade();
139     if (!context) {
140         LOGE("fail to get context, onAcquire failed.");
141         return;
142     }
143 
144     auto json = JsonUtil::Create(true);
145     json->Put("id", std::to_string(id).c_str());
146     LOGI("HandleOnAcquireEvent msg:%{public}s", json->ToString().c_str());
147     int32_t instance = context->GetInstanceId();
148     context->GetTaskExecutor()->PostTask(
149         [weak = WeakClaim(this), info = json->ToString(), instance] {
150             auto element = weak.Upgrade();
151             if (element != nullptr && element->onAcquireEvent_ != nullptr) {
152                 ContainerScope scope(instance);
153                 element->onAcquireEvent_(info);
154             }
155         },
156         TaskExecutor::TaskType::JS, "ArkUIFormHandleOnAcquireEvent");
157 }
158 
HandleOnRouterEvent(const std::unique_ptr<JsonValue> & action)159 void FormElement::HandleOnRouterEvent(const std::unique_ptr<JsonValue>& action)
160 {
161     if (!onRouterEvent_) {
162         LOGE("action could not find available event handle");
163         return;
164     }
165     auto context = context_.Upgrade();
166     if (!context) {
167         LOGE("fail to get context, onRouter failed.");
168         return;
169     }
170 
171     auto json = JsonUtil::Create(true);
172     json->Put("action", action);
173 
174     LOGI("HandleOnRouterEvent msg:%{public}s", json->ToString().c_str());
175     int32_t instance = context->GetInstanceId();
176     context->GetTaskExecutor()->PostTask(
177         [weak = WeakClaim(this), info = json->ToString(), instance] {
178             auto element = weak.Upgrade();
179             if (element != nullptr && element->onRouterEvent_ != nullptr) {
180                 ContainerScope scope(instance);
181                 element->onRouterEvent_(info);
182             }
183         },
184         TaskExecutor::TaskType::JS, "ArkUIFormHandleOnRouterEvent");
185 }
186 
HandleOnErrorEvent(const std::string code,const std::string msg)187 void FormElement::HandleOnErrorEvent(const std::string code, const std::string msg)
188 {
189     if (!onErrorEvent_) {
190         LOGE("could not find available event handle");
191         return;
192     }
193     auto context = context_.Upgrade();
194     if (!context) {
195         LOGE("fail to get context, onError failed.");
196         return;
197     }
198 
199     auto json = JsonUtil::Create(true);
200     json->Put("errcode", code.c_str());
201     json->Put("msg", msg.c_str());
202 
203     LOGI("HandleOnErrorEvent msg:%{public}s", msg.c_str());
204     int32_t instance = context->GetInstanceId();
205     context->GetTaskExecutor()->PostTask(
206         [weak = WeakClaim(this), info = json->ToString(), instance] {
207             auto element = weak.Upgrade();
208             if (element != nullptr && element->onErrorEvent_ != nullptr) {
209                 ContainerScope scope(instance);
210                 element->onErrorEvent_(info);
211             }
212         },
213         TaskExecutor::TaskType::JS, "ArkUIFormHandleOnErrorEvent");
214 }
215 
HandleOnUninstallEvent(int64_t formId)216 void FormElement::HandleOnUninstallEvent(int64_t formId)
217 {
218     if (!onUninstallEvent_) {
219         LOGE("could not find available event handle");
220         return;
221     }
222     auto context = context_.Upgrade();
223     if (!context) {
224         LOGE("fail to get context, onUninstall failed.");
225         return;
226     }
227 
228     auto json = JsonUtil::Create(true);
229     json->Put("id", std::to_string(formId).c_str());
230     LOGI("HandleOnUninstallEvent formId:%{public}s", std::to_string(formId).c_str());
231     int32_t instance = context->GetInstanceId();
232     context->GetTaskExecutor()->PostTask(
233         [weak = WeakClaim(this), info = json->ToString(), instance] {
234             auto element = weak.Upgrade();
235             if (element != nullptr && element->onUninstallEvent_ != nullptr) {
236                 ContainerScope scope(instance);
237                 element->onUninstallEvent_(info);
238             }
239         },
240         TaskExecutor::TaskType::JS, "ArkUIFormHandleOnUninstallEvent");
241 }
242 
Prepare(const WeakPtr<Element> & parent)243 void FormElement::Prepare(const WeakPtr<Element>& parent)
244 {
245     RenderElement::Prepare(parent);
246     auto context = context_.Upgrade();
247     if (!context) {
248         LOGE("fail to get context, onUninstall failed.");
249         return;
250     }
251 
252     if (!formManagerBridge_) {
253         formManagerBridge_ = AceType::MakeRefPtr<FormManagerDelegate>(GetContext());
254         int32_t instanceID = context->GetInstanceId();
255         auto formUtils = FormManager::GetInstance().GetFormUtils();
256         if (formUtils) {
257             formManagerBridge_->SetFormUtils(formUtils);
258         }
259         formManagerBridge_->AddFormAcquireCallback(
260             [weak = WeakClaim(this), instanceID](int64_t id, std::string path, std::string module, std::string data,
261                 std::map<std::string, sptr<AppExecFwk::FormAshmem>> imageDataMap, AppExecFwk::FormJsInfo formJsInfo,
262                 const FrontendType& frontendType, const FrontendType& uiSyntax) {
263                 ContainerScope scope(instanceID);
264                 auto element = weak.Upgrade();
265                 auto uiTaskExecutor = SingleTaskExecutor::Make(
266                     element->GetContext().Upgrade()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
267                 uiTaskExecutor.PostTask([id, path, module, data, imageDataMap, formJsInfo, weak,
268                                         instanceID, frontendType, uiSyntax] {
269                     ContainerScope scope(instanceID);
270                     auto form = weak.Upgrade();
271                     if (form) {
272                         auto container = form->GetSubContainer();
273                         if (container) {
274                             container->SetWindowConfig(
275                                 { formJsInfo.formWindow.designWidth, formJsInfo.formWindow.autoDesignWidth });
276                             container->RunCard(id, path, module, data, imageDataMap,
277                                                formJsInfo.formSrc, frontendType, uiSyntax);
278                         }
279                     }
280                 }, "ArkUIFormAcquireAndRunCard");
281             });
282         formManagerBridge_->AddFormUpdateCallback([weak = WeakClaim(this), instanceID](int64_t id, std::string data,
283             std::map<std::string, sptr<AppExecFwk::FormAshmem>> imageDataMap) {
284             ContainerScope scope(instanceID);
285             auto element = weak.Upgrade();
286             auto uiTaskExecutor = SingleTaskExecutor::Make(
287                 element->GetContext().Upgrade()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
288             uiTaskExecutor.PostTask([id, data, imageDataMap, weak, instanceID] {
289                 ContainerScope scope(instanceID);
290                 auto form = weak.Upgrade();
291                 if (form) {
292                     if (form->ISAllowUpdate()) {
293                         form->GetSubContainer()->UpdateCard(data, imageDataMap);
294                     }
295                 }
296             }, "ArkUIFormUpdateCard");
297         });
298         formManagerBridge_->AddFormErrorCallback(
299             [weak = WeakClaim(this), instanceID](std::string code, std::string msg) {
300                 ContainerScope scope(instanceID);
301                 auto element = weak.Upgrade();
302                 auto uiTaskExecutor = SingleTaskExecutor::Make(
303                     element->GetContext().Upgrade()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
304                 uiTaskExecutor.PostTask([code, msg, weak, instanceID] {
305                     ContainerScope scope(instanceID);
306                     auto form = weak.Upgrade();
307                     if (form) {
308                         form->HandleOnErrorEvent(code, msg);
309                     }
310 
311                     auto render = form->GetRenderNode();
312                     if (!render) {
313                         LOGE("remove card from screen fail, due to could not get card render node");
314                         return;
315                     }
316                     auto renderForm = AceType::DynamicCast<RenderForm>(render);
317                     if (renderForm) {
318                         renderForm->RemoveChildren();
319                     }
320                 }, "ArkUIFormRemoveCard");
321             });
322         formManagerBridge_->AddFormUninstallCallback(
323             [weak = WeakClaim(this), instanceID](int64_t formId) {
324                 ContainerScope scope(instanceID);
325                 auto element = weak.Upgrade();
326                 auto uiTaskExecutor = SingleTaskExecutor::Make(
327                     element->GetContext().Upgrade()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
328                 uiTaskExecutor.PostTask(
329                     [formId, weak, instanceID] {
330                         ContainerScope scope(instanceID);
331                         auto form = weak.Upgrade();
332                         if (form) {
333                             form->HandleOnUninstallEvent(formId);
334                         }
335                     }, "ArkUIFormUninstall");
336             });
337     }
338 }
339 
OnActionEvent(const std::string & action) const340 void FormElement::OnActionEvent(const std::string& action) const
341 {
342     LOGI("begin action event");
343     auto eventAction = JsonUtil::ParseJsonString(action);
344     if (!eventAction->IsValid()) {
345         LOGE("get event action failed");
346         return;
347     }
348     auto actionType = eventAction->GetValue("action");
349     if (!actionType->IsValid()) {
350         LOGE("get event key failed");
351         return;
352     }
353 
354     auto type = actionType->GetString();
355     if (type != "router" && type != "message") {
356         LOGE("undefined event type");
357         return;
358     }
359 
360 #ifndef OHOS_STANDARD_SYSTEM
361     if ("router" == type) {
362         HandleOnRouterEvent(eventAction);
363         return;
364     }
365 #endif
366 
367     if (formManagerBridge_) {
368         LOGI("send action event to ability.");
369         formManagerBridge_->OnActionEvent(action);
370     }
371 }
372 
CreateCardContainer()373 void FormElement::CreateCardContainer()
374 {
375     if (subContainer_) {
376         auto id = subContainer_->GetRunningCardId();
377         FormManager::GetInstance().RemoveSubContainer(id);
378 
379         subContainer_->Destroy();
380         subContainer_.Reset();
381     }
382 
383     auto context = GetContext().Upgrade();
384     if (!context) {
385         LOGE("get context fail.");
386         return;
387     }
388     subContainer_ = AceType::MakeRefPtr<SubContainer>(context, context->GetInstanceId());
389     if (!subContainer_) {
390         LOGE("create card container fail.");
391         return;
392     }
393     subContainer_->Initialize();
394     subContainer_->SetFormComponent(component_);
395     auto form = AceType::DynamicCast<FormComponent>(component_);
396     if (!form) {
397         LOGE("form component is null when try adding nonmatched container to form manager.");
398         return;
399     }
400 
401     auto formNode = AceType::DynamicCast<RenderForm>(renderNode_);
402     if (!formNode) {
403         LOGE("form node is null.");
404         return;
405     }
406     formNode->SetSubContainer(subContainer_);
407 
408     subContainer_->AddFormAcquireCallback([weak = WeakClaim(this)](int64_t id) {
409         auto element = weak.Upgrade();
410         auto uiTaskExecutor =
411             SingleTaskExecutor::Make(element->GetContext().Upgrade()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
412         uiTaskExecutor.PostTask([id, weak] {
413             auto form = weak.Upgrade();
414             if (form) {
415                 LOGI("card id:%{public}" PRId64, id);
416                 form->HandleOnAcquireEvent(id);
417             }
418         }, "ArkUIFormAcquire");
419     });
420 }
421 
CreateRenderNode()422 RefPtr<RenderNode> FormElement::CreateRenderNode()
423 {
424     return RenderForm::Create();
425 }
426 
427 } // namespace OHOS::Ace
428