1 /*
2 * Copyright (c) 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 "js_transition_controller.h"
17 #include "js_runtime_utils.h"
18 #include "window.h"
19 #include "window_helper.h"
20 #include "window_manager_hilog.h"
21 #include "window_option.h"
22 namespace OHOS {
23 namespace Rosen {
24 using namespace AbilityRuntime;
25 namespace {
26 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "JsTransitionController"};
27 }
28
29 static int jsTransCxtCtorCnt = 0;
30 static int jsTransCxtDtorCnt = 0;
31 static int jsTransCtrlCtorCnt = 0;
32 static int jsTransCtrlDtorCnt = 0;
33
JsTransitionContext(sptr<Window> window,bool isShownTransContext)34 JsTransitionContext::JsTransitionContext(sptr<Window> window, bool isShownTransContext)
35 : windowToken_(window), isShownTransContext_(isShownTransContext)
36 {
37 WLOGFI("[NAPI] JsTransitionContext constructorCnt: %{public}d", ++jsTransCxtCtorCnt);
38 }
39
~JsTransitionContext()40 JsTransitionContext::~JsTransitionContext()
41 {
42 WLOGFI("[NAPI] ~JsTransitionContext deConstructorCnt: %{public}d", ++jsTransCxtDtorCnt);
43 }
44
Finalizer(NativeEngine * engine,void * data,void * hint)45 void JsTransitionContext::Finalizer(NativeEngine* engine, void* data, void* hint)
46 {
47 WLOGFI("[NAPI]JsTransitionContext::Finalizer");
48 std::unique_ptr<JsTransitionContext>(static_cast<JsTransitionContext*>(data));
49 }
50
CompleteTransition(NativeEngine * engine,NativeCallbackInfo * info)51 NativeValue* JsTransitionContext::CompleteTransition(NativeEngine* engine, NativeCallbackInfo* info)
52 {
53 WLOGFI("[NAPI]CompleteTransition");
54 JsTransitionContext* me = CheckParamsAndGetThis<JsTransitionContext>(engine, info);
55 return (me != nullptr) ? me->OnCompleteTransition(*engine, *info) : nullptr;
56 }
57
OnCompleteTransition(NativeEngine & engine,NativeCallbackInfo & info)58 NativeValue* JsTransitionContext::OnCompleteTransition(NativeEngine& engine, NativeCallbackInfo& info)
59 {
60 WmErrorCode errCode = WmErrorCode::WM_OK;
61 if (info.argc < 1) {
62 errCode = WmErrorCode::WM_ERROR_INVALID_PARAM;
63 }
64 bool transitionCompleted = false;
65 if (errCode == WmErrorCode::WM_OK && !ConvertFromJsValue(engine, info.argv[0], transitionCompleted)) {
66 errCode = WmErrorCode::WM_ERROR_INVALID_PARAM;
67 }
68 if (errCode == WmErrorCode::WM_ERROR_INVALID_PARAM) {
69 engine.Throw(CreateJsError(engine, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
70 return engine.CreateUndefined();
71 }
72 WMError ret = WMError::WM_OK;
73 auto state = windowToken_->GetWindowState();
74 if (!isShownTransContext_) {
75 if (state != WindowState::STATE_HIDDEN) {
76 WLOGFI("[NAPI]Window [%{public}u, %{public}s] Hidden context called but window is not hidden: %{public}u",
77 windowToken_->GetWindowId(), windowToken_->GetWindowName().c_str(), static_cast<uint32_t>(state));
78 return engine.CreateUndefined();
79 }
80 windowToken_->UpdateSurfaceNodeAfterCustomAnimation(false); // remove from rs tree after animation
81 if (!transitionCompleted) {
82 ret = windowToken_->Show(); // hide aborted
83 }
84 } else {
85 if (state != WindowState::STATE_SHOWN) {
86 WLOGFI("[NAPI]Window [%{public}u, %{public}s] shown context called but window is not shown: %{public}u",
87 windowToken_->GetWindowId(), windowToken_->GetWindowName().c_str(), static_cast<uint32_t>(state));
88 return engine.CreateUndefined();
89 }
90 if (!transitionCompleted) {
91 ret = windowToken_->Hide(); // show aborted
92 }
93 }
94 if (ret != WMError::WM_OK) {
95 engine.Throw(CreateJsError(engine, static_cast<int32_t>(WM_JS_TO_ERROR_CODE_MAP.at(ret))));
96 return engine.CreateUndefined();
97 }
98 WLOGFI("[NAPI]Window [%{public}u, %{public}s] CompleteTransition %{public}d end",
99 windowToken_->GetWindowId(), windowToken_->GetWindowName().c_str(), transitionCompleted);
100 return engine.CreateUndefined();
101 }
102
CreateJsTransitionContextObject(NativeEngine & engine,std::shared_ptr<NativeReference> jsWin,sptr<Window> window,bool isShownTransContext)103 static NativeValue* CreateJsTransitionContextObject(NativeEngine& engine, std::shared_ptr<NativeReference> jsWin,
104 sptr<Window> window, bool isShownTransContext)
105 {
106 WLOGFI("[NAPI]CreateJsTransitionContextObject");
107 NativeValue *objValue = engine.CreateObject();
108 NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
109 if (object == nullptr) {
110 WLOGFE("[NAPI]Failed to get object");
111 return nullptr;
112 }
113 std::unique_ptr<JsTransitionContext> jsTransContext = std::make_unique<JsTransitionContext>(window,
114 isShownTransContext);
115 object->SetNativePointer(jsTransContext.release(), JsTransitionContext::Finalizer, nullptr);
116 if (jsWin != nullptr && jsWin->Get() != nullptr) {
117 object->SetProperty("toWindow", jsWin->Get());
118 } else {
119 WLOGFE("[NAPI]jsWin is nullptr");
120 return nullptr;
121 }
122
123 const char *moduleName = "JsTransitionContext";
124 BindNativeFunction(engine, *object, "completeTransition", moduleName, JsTransitionContext::CompleteTransition);
125 return objValue;
126 }
127
JsTransitionController(NativeEngine & engine,std::shared_ptr<NativeReference> jsWin,sptr<Window> window)128 JsTransitionController::JsTransitionController(NativeEngine& engine, std::shared_ptr<NativeReference> jsWin,
129 sptr<Window> window)
130 : engine_(engine), jsWin_(jsWin), windowToken_(window), weakRef_(wptr<JsTransitionController> (this))
131 {
132 WLOGFI("[NAPI] JsTransitionController constructorCnt: %{public}d", ++jsTransCtrlCtorCnt);
133 }
134
~JsTransitionController()135 JsTransitionController::~JsTransitionController()
136 {
137 WLOGFI("[NAPI] ~JsTransitionController deConstructorCnt: %{public}d", ++jsTransCtrlDtorCnt);
138 }
139
AnimationForShown()140 void JsTransitionController::AnimationForShown()
141 {
142 WLOGFI("[NAPI]AnimationForShown");
143 std::unique_ptr<AsyncTask::CompleteCallback> complete = std::make_unique<AsyncTask::CompleteCallback> (
144 [self = weakRef_](NativeEngine&, AsyncTask&, int32_t) {
145 auto thisController = self.promote();
146 if (thisController == nullptr) {
147 WLOGFE("this transition Controller is null!");
148 return;
149 }
150 HandleScope handleScope(thisController->engine_);
151 auto jsWin = thisController->jsWin_.lock();
152 auto window = thisController->windowToken_.promote();
153 if (jsWin == nullptr || window == nullptr) {
154 WLOGFE("native window or jsWindow is null!");
155 return;
156 }
157 auto state = window->GetWindowState();
158 if (state != WindowState::STATE_SHOWN) {
159 WLOGFE("animation shown configuration for state %{public}u not support!", static_cast<uint32_t>(state));
160 return;
161 }
162 NativeValue* jsTransContextObj = CreateJsTransitionContextObject(
163 thisController->engine_, jsWin, window, true);
164 if (jsTransContextObj == nullptr) {
165 return;
166 }
167 NativeValue *argv[] = { jsTransContextObj };
168 thisController->CallJsMethod("animationForShown", argv, ArraySize(argv));
169 // add to rs tree before animation
170 window->UpdateSurfaceNodeAfterCustomAnimation(true);
171 }
172 );
173
174 NativeReference* callback = nullptr;
175 std::unique_ptr<AsyncTask::ExecuteCallback> execute = nullptr;
176 AsyncTask::Schedule("JsTransitionController::AnimationForShown", engine_,
177 std::make_unique<AsyncTask>(callback, std::move(execute), std::move(complete)));
178 }
179
AnimationForHidden()180 void JsTransitionController::AnimationForHidden()
181 {
182 WLOGFI("[NAPI]AnimationForHidden");
183 std::unique_ptr<AsyncTask::CompleteCallback> complete = std::make_unique<AsyncTask::CompleteCallback> (
184 [self = weakRef_](NativeEngine&, AsyncTask&, int32_t) {
185 auto thisController = self.promote();
186 if (thisController == nullptr) {
187 WLOGFE("this transition Controller is null!");
188 return;
189 }
190 HandleScope handleScope(thisController->engine_);
191 auto jsWin = thisController->jsWin_.lock();
192 auto window = thisController->windowToken_.promote();
193 if (jsWin == nullptr || window == nullptr) {
194 WLOGFE("native window or jsWindow is null!");
195 return;
196 }
197 auto state = window->GetWindowState();
198 if (state != WindowState::STATE_HIDDEN) {
199 WLOGFE("animation hidden configuration for state %{public}u not support!",
200 static_cast<uint32_t>(state));
201 return;
202 }
203 NativeValue* jsTransContextObj = CreateJsTransitionContextObject(
204 thisController->engine_, jsWin, window, false);
205 if (jsTransContextObj == nullptr) {
206 return;
207 }
208 NativeValue *argv[] = { jsTransContextObj };
209 thisController->CallJsMethod("animationForHidden", argv, ArraySize(argv));
210 }
211 );
212 NativeReference* callback = nullptr;
213 std::unique_ptr<AsyncTask::ExecuteCallback> execute = nullptr;
214 AsyncTask::Schedule("JsTransitionController::AnimationForHidden", engine_,
215 std::make_unique<AsyncTask>(callback, std::move(execute), std::move(complete)));
216 }
217
CallJsMethod(const std::string & methodName,NativeValue * const * argv,size_t argc)218 void JsTransitionController::CallJsMethod(const std::string& methodName, NativeValue* const* argv, size_t argc)
219 {
220 WLOGFI("Call js function:%{public}s.", methodName.c_str());
221 auto self = jsTransControllerObj_.lock();
222 if (self == nullptr) {
223 WLOGFE("JsController is null!");
224 return;
225 }
226 auto jsControllerValue = self->Get();
227 auto jsControllerObj = ConvertNativeValueTo<NativeObject>(jsControllerValue);
228 if (jsControllerObj == nullptr) {
229 WLOGFE("JsControllerObj is null!");
230 return;
231 }
232 auto method = jsControllerObj->GetProperty(methodName.c_str());
233 if (method == nullptr || method->TypeOf() == NATIVE_UNDEFINED) {
234 WLOGFE("Failed to get %{public}s from object", methodName.c_str());
235 return;
236 }
237 engine_.CallFunction(jsControllerValue, method, argv, argc);
238 }
239
SetJsController(std::shared_ptr<NativeReference> jsVal)240 void JsTransitionController::SetJsController(std::shared_ptr<NativeReference> jsVal)
241 {
242 jsTransControllerObj_ = jsVal;
243 }
244 }
245 }