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