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