1 /*
2 * Copyright (c) 2025 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 #include "js_ui_effect_controller.h"
16
17 #include "js_runtime_utils.h"
18 #include "js_window_animation_utils.h"
19 #include "js_window.h"
20 #include "js_err_utils.h"
21 #include "ui_effect_controller_common.h"
22 #include "window_adapter.h"
23 #include "window_manager_hilog.h"
24
25 namespace OHOS::Rosen {
26 constexpr size_t ARGC_ONE = 1;
27 constexpr size_t ARGC_TWO = 2;
28 constexpr size_t ARGC_THREE = 3;
29 constexpr size_t INDEX_ZERO = 0;
30 constexpr size_t INDEX_ONE = 1;
31 constexpr size_t INDEX_TWO = 2;
32 constexpr size_t FOUR_PARAMS_SIZE = 4;
33 using namespace AbilityRuntime;
34
CreateJsObject(napi_env env,JsUIEffectController * filter,napi_value & obj)35 napi_status JsUIEffectController::CreateJsObject(napi_env env, JsUIEffectController* filter, napi_value& obj)
36 {
37 NAPI_CHECK(napi_create_object(env, &obj), "ui effect obj");
38 napi_status status = napi_wrap(env, obj, filter, JsUIEffectController::Finalizer, nullptr, nullptr);
39 if (status != napi_status::napi_ok) {
40 TLOGE(WmsLogTag::WMS_ANIMATION, "napi func failed, with reason %{public}d", status);
41 delete filter;
42 return status;
43 }
44 BindNativeFunctions(env, obj, "JsUIEffectController");
45 return napi_status::napi_ok;
46 }
47
Finalizer(napi_env env,void * data,void * hint)48 void JsUIEffectController::Finalizer(napi_env env, void* data, void* hint)
49 {
50 JsUIEffectController* controller = static_cast<JsUIEffectController*>(data);
51 if (controller != nullptr) {
52 delete controller;
53 }
54 }
55
JsUIEffectController()56 JsUIEffectController::JsUIEffectController(): client_(sptr<UIEffectControllerClient>::MakeSptr())
57 {
58 TLOGI(WmsLogTag::WMS_ANIMATION, "Constructor");
59 };
60
~JsUIEffectController()61 JsUIEffectController::~JsUIEffectController()
62 {
63 SingletonContainer::Get<WindowAdapter>().UnregisterUIEffectRecoverCallbackFunc(client_->GetId());
64 TLOGI(WmsLogTag::WMS_ANIMATION, "Destrutor, id: %{public}d", client_->GetId());
65 }
66
Init()67 WMError JsUIEffectController::Init()
68 {
69 WMError err = InitClientAndServer();
70 if (err != WMError::WM_OK) {
71 TLOGI(WmsLogTag::WMS_ANIMATION, "failed to init");
72 return err;
73 }
74 SingletonContainer::Get<WindowAdapter>().RegisterUIEffectRecoverCallbackFunc(client_->GetId(), [this]()-> WMError {
75 return InitClientAndServer();
76 });
77 return WMError::WM_OK;
78 }
79
InitClientAndServer()80 WMError JsUIEffectController::InitClientAndServer()
81 {
82 int32_t controllerId = UIEFFECT_INVALID_ID;
83 WMError err = SingletonContainer::Get<WindowAdapter>().CreateUIEffectController(client_, server_, controllerId);
84 if (err != WMError::WM_OK) {
85 return err;
86 }
87 client_->SetId(controllerId);
88 return WMError::WM_OK;
89 }
90
BindNativeFunctions(napi_env env,napi_value object,const char * moduleName)91 void JsUIEffectController::BindNativeFunctions(napi_env env, napi_value object, const char* moduleName)
92 {
93 BindNativeFunction(env, object, "setParams", moduleName, JsUIEffectController::SetParams);
94 BindNativeFunction(env, object, "animateToUIEffect", moduleName, JsUIEffectController::AnimateTo);
95 }
96
SetParams(napi_env env,napi_callback_info info)97 napi_value JsUIEffectController::SetParams(napi_env env, napi_callback_info info)
98 {
99 TLOGI(WmsLogTag::WMS_ANIMATION, "NapiFunc");
100 JsUIEffectController* me = CheckParamsAndGetThis<JsUIEffectController>(env, info);
101 return (me != nullptr) ? me->OnSetParams(env, info) : nullptr;
102 }
103
AnimateTo(napi_env env,napi_callback_info info)104 napi_value JsUIEffectController::AnimateTo(napi_env env, napi_callback_info info)
105 {
106 TLOGI(WmsLogTag::WMS_ANIMATION, "NapiFunc");
107 JsUIEffectController* me = CheckParamsAndGetThis<JsUIEffectController>(env, info);
108 return (me != nullptr) ? me->OnAnimateTo(env, info) : nullptr;
109 }
110
OnSetParams(napi_env env,napi_callback_info info)111 napi_value JsUIEffectController::OnSetParams(napi_env env, napi_callback_info info)
112 {
113 size_t argc = FOUR_PARAMS_SIZE;
114 napi_value argv[FOUR_PARAMS_SIZE] = {nullptr};
115 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
116 if (argc != ARGC_ONE) {
117 TLOGE(WmsLogTag::WMS_ATTRIBUTE, "Argc is invalid: %{public}zu", argc);
118 return NapiThrowError(env, WmErrorCode::WM_ERROR_INVALID_PARAM);
119 }
120 sptr<UIEffectParams> params = sptr<UIEffectParams>::MakeSptr();
121 if (params->ConvertFromJsValue(env, argv[INDEX_ZERO]) != napi_status::napi_ok) {
122 TLOGE(WmsLogTag::WMS_ATTRIBUTE, "parse ui effect params failed");
123 return NapiThrowError(env, WmErrorCode::WM_ERROR_INVALID_PARAM);
124 }
125 if (params->IsEmpty()) {
126 TLOGE(WmsLogTag::WMS_ANIMATION, "do not have any parameters");
127 return NapiThrowError(env, WmErrorCode::WM_ERROR_ILLEGAL_PARAM);
128 }
129 std::shared_ptr<WmErrorCode> errCodePtr = std::make_shared<WmErrorCode>(WmErrorCode::WM_ERROR_SYSTEM_ABNORMALLY);
130 NapiAsyncTask::ExecuteCallback execute = [params, client = client_, server = server_, errCodePtr] {
131 if (errCodePtr == nullptr || client == nullptr || server == nullptr || params == nullptr) {
132 return;
133 }
134 WMError ret = server->SetParams(params);
135 *errCodePtr = WM_JS_TO_ERROR_CODE_MAP.at(ret);
136 TLOGI(WmsLogTag::WMS_ANIMATION, "ui effect %{public}d set filter params exec end with err code %{public}d",
137 client->GetId(), ret);
138 };
139 NapiAsyncTask::CompleteCallback complete =
140 [errCodePtr](napi_env env, NapiAsyncTask& task, int32_t status) {
141 if (errCodePtr == nullptr) {
142 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY,
143 "System abnormal."));
144 return;
145 }
146 if (*errCodePtr == WmErrorCode::WM_OK) {
147 task.Resolve(env, NapiGetUndefined(env));
148 } else {
149 task.Reject(env, JsErrUtils::CreateJsError(env, *errCodePtr));
150 }
151 };
152 napi_value result = nullptr;
153 NapiAsyncTask::Schedule("JsUIEffect::SetParams",
154 env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
155 return result;
156 }
157
OnAnimateTo(napi_env env,napi_callback_info info)158 napi_value JsUIEffectController::OnAnimateTo(napi_env env, napi_callback_info info)
159 {
160 size_t argc = FOUR_PARAMS_SIZE;
161 napi_value argv[FOUR_PARAMS_SIZE] = {nullptr};
162 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
163 if (argc > ARGC_THREE || argc < ARGC_TWO) {
164 TLOGE(WmsLogTag::WMS_ANIMATION, "Argc is invalid: %{public}zu", argc);
165 return NapiThrowError(env, WmErrorCode::WM_ERROR_INVALID_PARAM);
166 }
167 struct AnimationInfoList {
168 sptr<UIEffectParams> params = sptr<UIEffectParams>::MakeSptr();
169 sptr<WindowAnimationOption> option = sptr<WindowAnimationOption>::MakeSptr();
170 sptr<WindowAnimationOption> interruptOption = nullptr;
171 WmErrorCode errCode = WmErrorCode::WM_OK;
172 };
173 std::shared_ptr<AnimationInfoList> lists = std::make_shared<AnimationInfoList>();
174 WmErrorCode err = WmErrorCode::WM_OK;
175 if (!ConvertWindowAnimationOptionFromJsValue(env, argv[INDEX_ZERO], *lists->option, err)) {
176 TLOGE(WmsLogTag::WMS_ANIMATION, "parse window animation config failed");
177 return NapiThrowError(env, err);
178 }
179 if (!CheckWindowAnimationOption(env, *lists->option, err)) {
180 TLOGE(WmsLogTag::WMS_ANIMATION, "check window animation config failed");
181 return NapiThrowError(env, err);
182 }
183 if (lists->params->ConvertFromJsValue(env, argv[INDEX_ONE]) != napi_status::napi_ok) {
184 TLOGE(WmsLogTag::WMS_ANIMATION, "parse ui effect params failed");
185 return NapiThrowError(env, WmErrorCode::WM_ERROR_INVALID_PARAM);
186 }
187 if (lists->params->IsEmpty()) {
188 TLOGE(WmsLogTag::WMS_ANIMATION, "do not have any parameters");
189 return NapiThrowError(env, WmErrorCode::WM_ERROR_ILLEGAL_PARAM);
190 }
191 if (argc == ARGC_THREE) {
192 lists->interruptOption = sptr<WindowAnimationOption>::MakeSptr();
193 if (!ConvertWindowAnimationOptionFromJsValue(env, argv[INDEX_TWO], *lists->interruptOption, err)) {
194 TLOGE(WmsLogTag::WMS_ANIMATION, "parse window animation config failed");
195 return NapiThrowError(env, err);
196 }
197 if (!CheckWindowAnimationOption(env, *lists->interruptOption, err)) {
198 TLOGE(WmsLogTag::WMS_ANIMATION, "check window animation config failed");
199 return NapiThrowError(env, err);
200 }
201 }
202 NapiAsyncTask::ExecuteCallback execute = [lists, client = client_, server = server_] {
203 if (lists == nullptr) {
204 return;
205 }
206 WMError ret = server->AnimateTo(lists->params, lists->option, lists->interruptOption);
207 lists->errCode = WM_JS_TO_ERROR_CODE_MAP.at(ret);
208 TLOGI(WmsLogTag::WMS_ANIMATION, "ui effect %{public}d animateTo, err code %{public}d",
209 client->GetId(), ret);
210 };
211 NapiAsyncTask::CompleteCallback complete =
212 [lists](napi_env env, NapiAsyncTask& task, int32_t status) {
213 if (lists == nullptr) {
214 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY,
215 "System abnormal."));
216 return;
217 }
218 if (lists->errCode == WmErrorCode::WM_OK) {
219 task.Resolve(env, NapiGetUndefined(env));
220 } else {
221 task.Reject(env, JsErrUtils::CreateJsError(env, lists->errCode));
222 }
223 };
224 napi_value result = nullptr;
225 NapiAsyncTask::Schedule("JsUIEffect::SetParams",
226 env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
227 return result;
228 }
229 }