• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     WLOGI("[NAPI] JsTransitionContext constructorCnt: %{public}d", ++jsTransCxtCtorCnt);
38 }
39 
~JsTransitionContext()40 JsTransitionContext::~JsTransitionContext()
41 {
42     WLOGI("[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     WLOGI("[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     WLOGI("[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 window = windowToken_.promote();
74     if (window == nullptr) {
75         engine.Throw(CreateJsError(engine, static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY)));
76         return engine.CreateUndefined();
77     }
78     auto state = window->GetWindowState();
79     if (!isShownTransContext_) {
80         if (state != WindowState::STATE_HIDDEN) {
81             WLOGI("[NAPI]Window [%{public}u, %{public}s] Hidden context called but window is not hidden: %{public}u",
82                 window->GetWindowId(), window->GetWindowName().c_str(), static_cast<uint32_t>(state));
83             return engine.CreateUndefined();
84         }
85         window->UpdateSurfaceNodeAfterCustomAnimation(false); // remove from rs tree after animation
86         if (!transitionCompleted) {
87             ret = window->Show(); // hide aborted
88         }
89     } else {
90         if (state != WindowState::STATE_SHOWN) {
91             WLOGI("[NAPI]Window [%{public}u, %{public}s] shown context called but window is not shown: %{public}u",
92                 window->GetWindowId(), window->GetWindowName().c_str(), static_cast<uint32_t>(state));
93             return engine.CreateUndefined();
94         }
95         if (!transitionCompleted) {
96             ret = window->Hide(); // show aborted
97         }
98     }
99     if (ret != WMError::WM_OK) {
100         engine.Throw(CreateJsError(engine, static_cast<int32_t>(WM_JS_TO_ERROR_CODE_MAP.at(ret))));
101         return engine.CreateUndefined();
102     }
103     WLOGI("[NAPI]Window [%{public}u, %{public}s] CompleteTransition %{public}d end",
104         window->GetWindowId(), window->GetWindowName().c_str(), transitionCompleted);
105     return engine.CreateUndefined();
106 }
107 
CreateJsTransitionContextObject(NativeEngine & engine,std::shared_ptr<NativeReference> jsWin,sptr<Window> window,bool isShownTransContext)108 static NativeValue* CreateJsTransitionContextObject(NativeEngine& engine, std::shared_ptr<NativeReference> jsWin,
109     sptr<Window> window, bool isShownTransContext)
110 {
111     WLOGI("[NAPI]CreateJsTransitionContextObject");
112     NativeValue *objValue = engine.CreateObject();
113     NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
114     if (object == nullptr) {
115         WLOGFE("[NAPI]Failed to get object");
116         return nullptr;
117     }
118     std::unique_ptr<JsTransitionContext> jsTransContext = std::make_unique<JsTransitionContext>(window,
119         isShownTransContext);
120     object->SetNativePointer(jsTransContext.release(), JsTransitionContext::Finalizer, nullptr);
121     if (jsWin != nullptr && jsWin->Get() != nullptr) {
122         object->SetProperty("toWindow", jsWin->Get());
123     } else {
124         WLOGFE("[NAPI]jsWin is nullptr");
125         return nullptr;
126     }
127 
128     const char *moduleName = "JsTransitionContext";
129     BindNativeFunction(engine, *object, "completeTransition", moduleName, JsTransitionContext::CompleteTransition);
130     return objValue;
131 }
132 
JsTransitionController(NativeEngine & engine,std::shared_ptr<NativeReference> jsWin,sptr<Window> window)133 JsTransitionController::JsTransitionController(NativeEngine& engine, std::shared_ptr<NativeReference> jsWin,
134     sptr<Window> window)
135     : engine_(engine), jsWin_(jsWin), windowToken_(window), weakRef_(wptr<JsTransitionController> (this))
136 {
137     WLOGI("[NAPI] JsTransitionController constructorCnt: %{public}d", ++jsTransCtrlCtorCnt);
138 }
139 
~JsTransitionController()140 JsTransitionController::~JsTransitionController()
141 {
142     WLOGI("[NAPI] ~JsTransitionController deConstructorCnt: %{public}d", ++jsTransCtrlDtorCnt);
143 }
144 
AnimationForShown()145 void JsTransitionController::AnimationForShown()
146 {
147     WLOGI("[NAPI]AnimationForShown");
148     std::unique_ptr<AsyncTask::CompleteCallback> complete = std::make_unique<AsyncTask::CompleteCallback> (
149         [self = weakRef_](NativeEngine&, AsyncTask&, int32_t) {
150             auto thisController = self.promote();
151             if (thisController == nullptr) {
152                 WLOGFE("this transition Controller is null!");
153                 return;
154             }
155             HandleScope handleScope(thisController->engine_);
156             auto jsWin = thisController->jsWin_.lock();
157             auto window = thisController->windowToken_.promote();
158             if (jsWin == nullptr || window == nullptr) {
159                 WLOGFE("native window or jsWindow is null!");
160                 return;
161             }
162             auto state = window->GetWindowState();
163             if (state != WindowState::STATE_SHOWN) {
164                 WLOGFE("animation shown configuration for state %{public}u not support!", static_cast<uint32_t>(state));
165                 return;
166             }
167             NativeValue* jsTransContextObj = CreateJsTransitionContextObject(
168                 thisController->engine_, jsWin, window, true);
169             if (jsTransContextObj == nullptr) {
170                 return;
171             }
172             NativeValue *argv[] = { jsTransContextObj };
173             thisController->CallJsMethod("animationForShown", argv, ArraySize(argv));
174             // add to rs tree before animation
175             window->UpdateSurfaceNodeAfterCustomAnimation(true);
176         }
177     );
178 
179     NativeReference* callback = nullptr;
180     std::unique_ptr<AsyncTask::ExecuteCallback> execute = nullptr;
181     AsyncTask::Schedule("JsTransitionController::AnimationForShown", engine_,
182         std::make_unique<AsyncTask>(callback, std::move(execute), std::move(complete)));
183 }
184 
AnimationForHidden()185 void JsTransitionController::AnimationForHidden()
186 {
187     WLOGI("[NAPI]AnimationForHidden");
188     std::unique_ptr<AsyncTask::CompleteCallback> complete = std::make_unique<AsyncTask::CompleteCallback> (
189         [self = weakRef_](NativeEngine&, AsyncTask&, int32_t) {
190             auto thisController = self.promote();
191             if (thisController == nullptr) {
192                 WLOGFE("this transition Controller is null!");
193                 return;
194             }
195             HandleScope handleScope(thisController->engine_);
196             auto jsWin = thisController->jsWin_.lock();
197             auto window = thisController->windowToken_.promote();
198             if (jsWin == nullptr || window == nullptr) {
199                 WLOGFE("native window or jsWindow is null!");
200                 return;
201             }
202             auto state = window->GetWindowState();
203             if (state != WindowState::STATE_HIDDEN) {
204                 WLOGFE("animation hidden configuration for state %{public}u not support!",
205                     static_cast<uint32_t>(state));
206                 return;
207             }
208             NativeValue* jsTransContextObj = CreateJsTransitionContextObject(
209                 thisController->engine_, jsWin, window, false);
210             if (jsTransContextObj == nullptr) {
211                 return;
212             }
213             NativeValue *argv[] = { jsTransContextObj };
214             thisController->CallJsMethod("animationForHidden", argv, ArraySize(argv));
215         }
216     );
217     NativeReference* callback = nullptr;
218     std::unique_ptr<AsyncTask::ExecuteCallback> execute = nullptr;
219     AsyncTask::Schedule("JsTransitionController::AnimationForHidden", engine_,
220         std::make_unique<AsyncTask>(callback, std::move(execute), std::move(complete)));
221 }
222 
CallJsMethod(const std::string & methodName,NativeValue * const * argv,size_t argc)223 void JsTransitionController::CallJsMethod(const std::string& methodName, NativeValue* const* argv, size_t argc)
224 {
225     WLOGI("Call js function:%{public}s.", methodName.c_str());
226     auto self = jsTransControllerObj_.lock();
227     if (self == nullptr) {
228         WLOGFE("JsController is null!");
229         return;
230     }
231     auto jsControllerValue = self->Get();
232     auto jsControllerObj = ConvertNativeValueTo<NativeObject>(jsControllerValue);
233     if (jsControllerObj == nullptr) {
234         WLOGFE("JsControllerObj is null!");
235         return;
236     }
237     auto method = jsControllerObj->GetProperty(methodName.c_str());
238     if (method == nullptr || method->TypeOf() == NATIVE_UNDEFINED) {
239         WLOGFE("Failed to get %{public}s from object", methodName.c_str());
240         return;
241     }
242     engine_.CallFunction(jsControllerValue, method, argv, argc);
243 }
244 
SetJsController(std::shared_ptr<NativeReference> jsVal)245 void JsTransitionController::SetJsController(std::shared_ptr<NativeReference> jsVal)
246 {
247     jsTransControllerObj_ = jsVal;
248 }
249 }
250 }