1 /*
2  * Copyright (c) 2023 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_screen_session.h"
17 
18 #include <hitrace_meter.h>
19 #include <js_runtime_utils.h>
20 
21 #include "interfaces/include/ws_common.h"
22 #include "js_screen_utils.h"
23 #include "window_manager_hilog.h"
24 #include "singleton_container.h"
25 #include "screen_manager.h"
26 
27 namespace OHOS::Rosen {
28 using namespace AbilityRuntime;
29 namespace {
30 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "JsScreenSession" };
31 const std::string ON_CONNECTION_CALLBACK = "connect";
32 const std::string ON_DISCONNECTION_CALLBACK = "disconnect";
33 const std::string ON_PROPERTY_CHANGE_CALLBACK = "propertyChange";
34 const std::string ON_POWER_STATUS_CHANGE_CALLBACK = "powerStatusChange";
35 const std::string ON_SENSOR_ROTATION_CHANGE_CALLBACK = "sensorRotationChange";
36 const std::string ON_SCREEN_ORIENTATION_CHANGE_CALLBACK = "screenOrientationChange";
37 const std::string ON_SCREEN_ROTATION_LOCKED_CHANGE = "screenRotationLockedChange";
38 const std::string ON_SCREEN_DENSITY_CHANGE = "screenDensityChange";
39 const std::string ON_HOVER_STATUS_CHANGE_CALLBACK = "hoverStatusChange";
40 const std::string ON_SCREEN_CAPTURE_NOTIFY = "screenCaptureNotify";
41 const std::string ON_CAMERA_FOLD_STATUS_CHANGE_CALLBACK = "cameraStatusChange";
42 constexpr size_t ARGC_ONE = 1;
43 } // namespace
44 
Create(napi_env env,const sptr<ScreenSession> & screenSession)45 napi_value JsScreenSession::Create(napi_env env, const sptr<ScreenSession>& screenSession)
46 {
47     WLOGD("Create.");
48     napi_value objValue = nullptr;
49     napi_create_object(env, &objValue);
50     if (objValue == nullptr) {
51         WLOGFE("[NAPI]Object is null!");
52         return NapiGetUndefined(env);
53     }
54 
55     auto jsScreenSession = std::make_unique<JsScreenSession>(env, screenSession);
56     napi_wrap(env, objValue, jsScreenSession.release(), JsScreenSession::Finalizer, nullptr, nullptr);
57     napi_set_named_property(env, objValue, "screenId",
58         CreateJsValue(env, static_cast<int64_t>(screenSession->GetScreenId())));
59     napi_set_named_property(env, objValue, "name",
60         CreateJsValue(env, static_cast<std::string>(screenSession->GetName())));
61 
62     const char* moduleName = "JsScreenSession";
63     BindNativeFunction(env, objValue, "on", moduleName, JsScreenSession::RegisterCallback);
64     BindNativeFunction(env, objValue, "setScreenRotationLocked", moduleName,
65         JsScreenSession::SetScreenRotationLocked);
66     BindNativeFunction(env, objValue, "setTouchEnabled", moduleName,
67         JsScreenSession::SetTouchEnabled);
68     BindNativeFunction(env, objValue, "loadContent", moduleName, JsScreenSession::LoadContent);
69     return objValue;
70 }
71 
Finalizer(napi_env env,void * data,void * hint)72 void JsScreenSession::Finalizer(napi_env env, void* data, void* hint)
73 {
74     WLOGD("Finalizer.");
75     std::unique_ptr<JsScreenSession>(static_cast<JsScreenSession*>(data));
76 }
77 
JsScreenSession(napi_env env,const sptr<ScreenSession> & screenSession)78 JsScreenSession::JsScreenSession(napi_env env, const sptr<ScreenSession>& screenSession)
79     : env_(env), screenSession_(screenSession)
80 {
81     std::string name = screenSession_ ? screenSession_->GetName() : "UNKNOWN";
82     screenScene_ = new(std::nothrow) ScreenScene(name);
83     if (screenSession_) {
84         SetScreenSceneDpiFunc func = [this](float density) {
85             TLOGI(WmsLogTag::DMS, "Screen Scene Dpi change, new density = %{public}f", density);
86             if (!screenScene_ || !screenSession_) {
87                 TLOGE(WmsLogTag::DMS, "[NAPI]screenScene or screenSession is nullptr");
88                 return;
89             }
90             auto screenBounds = screenSession_->GetScreenProperty().GetBounds();
91             Rect rect = { screenBounds.rect_.left_, screenBounds.rect_.top_,
92                 screenBounds.rect_.width_, screenBounds.rect_.height_ };
93             screenScene_->SetDisplayDensity(density);
94             screenScene_->UpdateViewportConfig(rect, WindowSizeChangeReason::UPDATE_DPI_SYNC);
95             OnScreenDensityChange();
96         };
97         screenSession_->SetScreenSceneDpiChangeListener(func);
98         DestroyScreenSceneFunc destroyFunc = [screenScene = screenScene_]() {
99             if (screenScene) {
100                 screenScene->Destroy();
101             }
102         };
103         screenSession_->SetScreenSceneDestroyListener(destroyFunc);
104     }
105 }
106 
~JsScreenSession()107 JsScreenSession::~JsScreenSession()
108 {
109     WLOGI("~JsScreenSession");
110 }
111 
LoadContent(napi_env env,napi_callback_info info)112 napi_value JsScreenSession::LoadContent(napi_env env, napi_callback_info info)
113 {
114     JsScreenSession* me = CheckParamsAndGetThis<JsScreenSession>(env, info);
115     return (me != nullptr) ? me->OnLoadContent(env, info) : nullptr;
116 }
117 
OnLoadContent(napi_env env,napi_callback_info info)118 napi_value JsScreenSession::OnLoadContent(napi_env env, napi_callback_info info)
119 {
120     TLOGD(WmsLogTag::DMS, "[NAPI]JsScreenSession::OnLoadContent");
121     size_t argc = 4;
122     napi_value argv[4] = {nullptr}; // 4: params num
123     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
124     if (argc < 2) {  // 2: params num
125         TLOGE(WmsLogTag::DMS, "[NAPI]Argc is invalid: %{public}zu", argc);
126         napi_throw(env, CreateJsError(env, static_cast<int32_t>(WSErrorCode::WS_ERROR_INVALID_PARAM),
127             "Input parameter is missing or invalid"));
128         return NapiGetUndefined(env);
129     }
130     std::string contentUrl;
131     napi_value context = argv[1]; // 1: context param index
132     napi_value storage = argc < 3 ? nullptr : argv[2]; // 3: params num; 2: storage param index
133     if (!ConvertFromJsValue(env, argv[0], contentUrl)) { // 0: page path param index
134         TLOGE(WmsLogTag::DMS, "[NAPI]Failed to convert parameter to content url");
135         napi_throw(env, CreateJsError(env, static_cast<int32_t>(WSErrorCode::WS_ERROR_INVALID_PARAM),
136             "Input parameter is missing or invalid"));
137         return NapiGetUndefined(env);
138     }
139 
140     if (context == nullptr) {
141         TLOGE(WmsLogTag::DMS, "[NAPI]Failed to get context object");
142         napi_throw(env, CreateJsError(env, static_cast<int32_t>(WSErrorCode::WS_ERROR_STATE_ABNORMALLY)));
143         return NapiGetUndefined(env);
144     }
145     void* pointerResult = nullptr;
146     napi_unwrap(env, context, &pointerResult);
147     auto contextNativePointer = static_cast<std::weak_ptr<Context>*>(pointerResult);
148     if (contextNativePointer == nullptr) {
149         TLOGE(WmsLogTag::DMS, "[NAPI]Failed to get context pointer from js object");
150         napi_throw(env, CreateJsError(env, static_cast<int32_t>(WSErrorCode::WS_ERROR_STATE_ABNORMALLY)));
151         return NapiGetUndefined(env);
152     }
153     auto contextWeakPtr = *contextNativePointer;
154 
155     std::shared_ptr<NativeReference> contentStorage = nullptr;
156     if (storage != nullptr) {
157         napi_ref ref = nullptr;
158         napi_create_reference(env, storage, 1, &ref);
159         contentStorage = std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref));
160     }
161 
162     return ScheduleLoadContentTask(env, contentUrl, contextWeakPtr, contentStorage);
163 }
164 
ScheduleLoadContentTask(napi_env env,const std::string & contentUrl,std::weak_ptr<Context> contextWeakPtr,std::shared_ptr<NativeReference> contentStorage)165 napi_value JsScreenSession::ScheduleLoadContentTask(napi_env env, const std::string& contentUrl,
166     std::weak_ptr<Context> contextWeakPtr, std::shared_ptr<NativeReference> contentStorage)
167 {
168     if (screenScene_ == nullptr) {
169         TLOGE(WmsLogTag::DMS, "[NAPI]screenScene is nullptr");
170         return NapiGetUndefined(env);
171     }
172     napi_value nativeStorage = contentStorage ? contentStorage->GetNapiValue() : nullptr;
173     screenScene_->LoadContent(contentUrl, env, nativeStorage, contextWeakPtr.lock().get());
174     if (screenSession_) {
175         screenSession_->SetScreenSceneDpi(screenSession_->GetScreenProperty().GetVirtualPixelRatio());
176     }
177     return NapiGetUndefined(env);
178 }
179 
SetScreenRotationLocked(napi_env env,napi_callback_info info)180 napi_value JsScreenSession::SetScreenRotationLocked(napi_env env, napi_callback_info info)
181 {
182     JsScreenSession* me = CheckParamsAndGetThis<JsScreenSession>(env, info);
183     return (me != nullptr) ? me->OnSetScreenRotationLocked(env, info) : nullptr;
184 }
185 
OnSetScreenRotationLocked(napi_env env,napi_callback_info info)186 napi_value JsScreenSession::OnSetScreenRotationLocked(napi_env env, napi_callback_info info)
187 {
188     WLOGI("JsScreenSession::OnSetScreenRotationLocked is called");
189     size_t argc = 4;
190     napi_value argv[4] = {nullptr};
191     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
192     if (argc < 1) {
193         WLOGFE("[NAPI]Argc is invalid: %{public}zu", argc);
194         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
195         return NapiGetUndefined(env);
196     }
197     bool isLocked = true;
198     napi_value nativeVal = argv[0];
199     if (nativeVal == nullptr) {
200         WLOGFE("ConvertNativeValueTo isLocked failed!");
201         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
202         return NapiGetUndefined(env);
203     }
204     napi_get_value_bool(env, nativeVal, &isLocked);
205     if (screenSession_ == nullptr) {
206         WLOGFE("Failed to register screen change listener, session is null!");
207         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
208         return NapiGetUndefined(env);
209     }
210     screenSession_->SetScreenRotationLockedFromJs(isLocked);
211     NapiAsyncTask::CompleteCallback complete =
212         [isLocked](napi_env env, NapiAsyncTask& task, int32_t status) {
213             auto res = DM_JS_TO_ERROR_CODE_MAP.at(
214                 SingletonContainer::Get<ScreenManager>().SetScreenRotationLockedFromJs(isLocked));
215             if (res == DmErrorCode::DM_OK) {
216                 task.Resolve(env, NapiGetUndefined(env));
217                 WLOGFI("OnSetScreenRotationLocked success");
218             } else {
219                 task.Reject(env, CreateJsError(env, static_cast<int32_t>(res),
220                                                   "JsScreenSession::OnSetScreenRotationLocked failed."));
221                 WLOGFE("OnSetScreenRotationLocked failed");
222             }
223         };
224     napi_value result = nullptr;
225     NapiAsyncTask::Schedule("JsScreenSession::OnSetScreenRotationLocked",
226         env, CreateAsyncTaskWithLastParam(env, nullptr, nullptr, std::move(complete), &result));
227     WLOGFI("SetScreenRotationLocked %{public}u success.", static_cast<uint32_t>(isLocked));
228     return result;
229 }
230 
SetTouchEnabled(napi_env env,napi_callback_info info)231 napi_value JsScreenSession::SetTouchEnabled(napi_env env, napi_callback_info info)
232 {
233     JsScreenSession* me = CheckParamsAndGetThis<JsScreenSession>(env, info);
234     return (me != nullptr) ? me->OnSetTouchEnabled(env, info) : nullptr;
235 }
236 
OnSetTouchEnabled(napi_env env,napi_callback_info info)237 napi_value JsScreenSession::OnSetTouchEnabled(napi_env env, napi_callback_info info)
238 {
239     TLOGI(WmsLogTag::WMS_EVENT, "napi called");
240     size_t argc = 4;
241     napi_value argv[4] = {nullptr};
242     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
243     if (argc != ARGC_ONE) {
244         TLOGE(WmsLogTag::WMS_EVENT, "[NAPI]Argc is invalid: %{public}zu", argc);
245         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
246         return NapiGetUndefined(env);
247     }
248     bool isTouchEnabled = true;
249     napi_value nativeVal = argv[0];
250     if (nativeVal == nullptr) {
251         TLOGE(WmsLogTag::WMS_EVENT, "ConvertNativeValueTo isTouchEnabled failed!");
252         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
253         return NapiGetUndefined(env);
254     }
255     napi_get_value_bool(env, nativeVal, &isTouchEnabled);
256     if (screenSession_ == nullptr) {
257         TLOGE(WmsLogTag::WMS_EVENT, "Failed to register screen change listener, session is null!");
258         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
259         return NapiGetUndefined(env);
260     }
261     screenSession_->SetTouchEnabledFromJs(isTouchEnabled);
262     return NapiGetUndefined(env);
263 }
264 
RegisterScreenChangeListener()265 void JsScreenSession::RegisterScreenChangeListener()
266 {
267     if (screenSession_ == nullptr) {
268         WLOGFE("Failed to register screen change listener, session is null!");
269         return;
270     }
271 
272     screenSession_->RegisterScreenChangeListener(this);
273     WLOGFI("register screen change listener success.");
274 }
275 
RegisterCallback(napi_env env,napi_callback_info info)276 napi_value JsScreenSession::RegisterCallback(napi_env env, napi_callback_info info)
277 {
278     WLOGD("Register callback.");
279     JsScreenSession* me = CheckParamsAndGetThis<JsScreenSession>(env, info);
280     return (me != nullptr) ? me->OnRegisterCallback(env, info) : nullptr;
281 }
282 
UnRegisterScreenChangeListener()283 void JsScreenSession::UnRegisterScreenChangeListener()
284 {
285     if (screenSession_ == nullptr) {
286         WLOGFE("Failed to unregister screen change listener, session is null!");
287         return;
288     }
289 
290     screenSession_->UnregisterScreenChangeListener(this);
291     WLOGFI("unregister screen change listener success.");
292 }
293 
294 
OnRegisterCallback(napi_env env,napi_callback_info info)295 napi_value JsScreenSession::OnRegisterCallback(napi_env env, napi_callback_info info)
296 {
297     WLOGI("On register callback.");
298     size_t argc = 4;
299     napi_value argv[4] = {nullptr};
300     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
301     if (argc < 2) { // 2: params num
302         WLOGFE("Argc is invalid: %{public}zu", argc);
303         napi_throw(env, CreateJsError(env, static_cast<int32_t>(WSErrorCode::WS_ERROR_INVALID_PARAM)));
304         return NapiGetUndefined(env);
305     }
306 
307     std::string callbackType;
308     if (!ConvertFromJsValue(env, argv[0], callbackType)) {
309         WLOGFE("Failed to convert parameter to callback type.");
310         napi_throw(env, CreateJsError(env, static_cast<int32_t>(WSErrorCode::WS_ERROR_INVALID_PARAM)));
311         return NapiGetUndefined(env);
312     }
313 
314     napi_value callback = argv[1];
315     if (!NapiIsCallable(env, callback)) {
316         WLOGFE("Failed to register callback, callback is not callable!");
317         napi_throw(env, CreateJsError(env, static_cast<int32_t>(WSErrorCode::WS_ERROR_INVALID_PARAM)));
318         return NapiGetUndefined(env);
319     }
320 
321     if (mCallback_.count(callbackType)) {
322         WLOGFE("Failed to register callback, callback is already existed!");
323         napi_throw(env, CreateJsError(env, static_cast<int32_t>(WSErrorCode::WS_ERROR_REPEAT_OPERATION)));
324         return NapiGetUndefined(env);
325     }
326 
327     napi_ref result = nullptr;
328     napi_create_reference(env, callback, 1, &result);
329     std::shared_ptr<NativeReference> callbackRef(reinterpret_cast<NativeReference*>(result));
330     mCallback_[callbackType] = callbackRef;
331     RegisterScreenChangeListener();
332 
333     return NapiGetUndefined(env);
334 }
335 
CallJsCallback(const std::string & callbackType)336 void JsScreenSession::CallJsCallback(const std::string& callbackType)
337 {
338     WLOGI("Call js callback: %{public}s.", callbackType.c_str());
339     if (mCallback_.count(callbackType) == 0) {
340         WLOGFE("Callback is unregistered!");
341         return;
342     }
343 
344     if (callbackType == ON_DISCONNECTION_CALLBACK) {
345         WLOGFE("Call js callback %{public}s start", callbackType.c_str());
346         UnRegisterScreenChangeListener();
347     }
348 
349     auto jsCallbackRef = mCallback_[callbackType];
350     wptr<ScreenSession> screenSessionWeak(screenSession_);
351     auto complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
352         [jsCallbackRef, callbackType, screenSessionWeak](napi_env env, NapiAsyncTask& task, int32_t status) {
353             if (jsCallbackRef == nullptr) {
354                 WLOGFE("Call js callback %{public}s failed, jsCallbackRef is null!", callbackType.c_str());
355                 return;
356             }
357             auto method = jsCallbackRef->GetNapiValue();
358             if (method == nullptr) {
359                 WLOGFE("Call js callback %{public}s failed, method is null!", callbackType.c_str());
360                 return;
361             }
362             if (callbackType == ON_CONNECTION_CALLBACK || callbackType == ON_DISCONNECTION_CALLBACK) {
363                 auto screenSession = screenSessionWeak.promote();
364                 if (screenSession == nullptr) {
365                     WLOGFE("Call js callback %{public}s failed, screenSession is null!", callbackType.c_str());
366                     return;
367                 }
368                 napi_value argv[] = { JsScreenUtils::CreateJsScreenProperty(
369                     env, screenSession->GetScreenProperty()) };
370                 napi_call_function(env, NapiGetUndefined(env), method, ArraySize(argv), argv, nullptr);
371             } else {
372                 napi_value argv[] = {};
373                 napi_call_function(env, NapiGetUndefined(env), method, 0, argv, nullptr);
374             }
375             WLOGI("The js callback has been executed: %{public}s.", callbackType.c_str());
376         });
377 
378     napi_ref callback = nullptr;
379     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
380     NapiAsyncTask::Schedule("JsScreenSession::" + callbackType, env_,
381         std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
382 }
383 
OnConnect(ScreenId screenId)384 void JsScreenSession::OnConnect(ScreenId screenId)
385 {
386     CallJsCallback(ON_CONNECTION_CALLBACK);
387 }
388 
OnDisconnect(ScreenId screenId)389 void JsScreenSession::OnDisconnect(ScreenId screenId)
390 {
391     CallJsCallback(ON_DISCONNECTION_CALLBACK);
392 }
393 
OnSensorRotationChange(float sensorRotation,ScreenId screenId)394 void JsScreenSession::OnSensorRotationChange(float sensorRotation, ScreenId screenId)
395 {
396     const std::string callbackType = ON_SENSOR_ROTATION_CHANGE_CALLBACK;
397     if (mCallback_.count(callbackType) == 0) {
398         WLOGFE("Callback %{public}s is unregistered!", callbackType.c_str());
399         return;
400     }
401 
402     auto jsCallbackRef = mCallback_[callbackType];
403     wptr<ScreenSession> screenSessionWeak(screenSession_);
404     auto napiTask = [jsCallbackRef, callbackType, screenSessionWeak, sensorRotation, env = env_]() {
405         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "jsScreenSession::OnSensorRotationChange");
406         if (jsCallbackRef == nullptr) {
407             WLOGFE("Call js callback %{public}s failed, jsCallbackRef is null!", callbackType.c_str());
408             return;
409         }
410         auto method = jsCallbackRef->GetNapiValue();
411         if (method == nullptr) {
412             WLOGFE("Call js callback %{public}s failed, method is null!", callbackType.c_str());
413             return;
414         }
415         auto screenSession = screenSessionWeak.promote();
416         if (screenSession == nullptr) {
417             WLOGFE("Call js callback %{public}s failed, screenSession is null!", callbackType.c_str());
418             return;
419         }
420         napi_value argv[] = { CreateJsValue(env, sensorRotation) };
421         napi_call_function(env, NapiGetUndefined(env), method, ArraySize(argv), argv, nullptr);
422     };
423 
424     if (env_ != nullptr) {
425         napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate);
426         if (ret != napi_status::napi_ok) {
427             WLOGFE("OnSensorRotationChange: Failed to SendEvent.");
428         }
429     } else {
430         WLOGFE("OnSensorRotationChange: env is nullptr");
431     }
432 }
433 
OnScreenOrientationChange(float screenOrientation,ScreenId screenId)434 void JsScreenSession::OnScreenOrientationChange(float screenOrientation, ScreenId screenId)
435 {
436     const std::string callbackType = ON_SCREEN_ORIENTATION_CHANGE_CALLBACK;
437     WLOGI("Call js callback: %{public}s.", callbackType.c_str());
438     if (mCallback_.count(callbackType) == 0) {
439         WLOGFE("Callback %{public}s is unregistered!", callbackType.c_str());
440         return;
441     }
442 
443     auto jsCallbackRef = mCallback_[callbackType];
444     wptr<ScreenSession> screenSessionWeak(screenSession_);
445     auto complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
446         [jsCallbackRef, callbackType, screenSessionWeak, screenOrientation](
447             napi_env env, NapiAsyncTask& task, int32_t status) {
448             if (jsCallbackRef == nullptr) {
449                 WLOGFE("Call js callback %{public}s failed, jsCallbackRef is null!", callbackType.c_str());
450                 return;
451             }
452             auto method = jsCallbackRef->GetNapiValue();
453             if (method == nullptr) {
454                 WLOGFE("Call js callback %{public}s failed, method is null!", callbackType.c_str());
455                 return;
456             }
457             auto screenSession = screenSessionWeak.promote();
458             if (screenSession == nullptr) {
459                 WLOGFE("Call js callback %{public}s failed, screenSession is null!", callbackType.c_str());
460                 return;
461             }
462             napi_value argv[] = { CreateJsValue(env, screenOrientation) };
463             napi_call_function(env, NapiGetUndefined(env), method, ArraySize(argv), argv, nullptr);
464         });
465 
466     napi_ref callback = nullptr;
467     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
468     NapiAsyncTask::Schedule("JsScreenSession::" + callbackType, env_,
469         std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
470 }
471 
OnPropertyChange(const ScreenProperty & newProperty,ScreenPropertyChangeReason reason,ScreenId screenId)472 void JsScreenSession::OnPropertyChange(const ScreenProperty& newProperty, ScreenPropertyChangeReason reason,
473     ScreenId screenId)
474 {
475     const std::string callbackType = ON_PROPERTY_CHANGE_CALLBACK;
476     WLOGD("Call js callback: %{public}s.", callbackType.c_str());
477     if (mCallback_.count(callbackType) == 0) {
478         WLOGFE("Callback %{public}s is unregistered!", callbackType.c_str());
479         return;
480     }
481 
482     auto jsCallbackRef = mCallback_[callbackType];
483     wptr<ScreenSession> screenSessionWeak(screenSession_);
484     auto napiTask = [jsCallbackRef, callbackType, screenSessionWeak, newProperty, reason, env = env_]() {
485         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "jsScreenSession::OnPropertyChange");
486         if (jsCallbackRef == nullptr) {
487             WLOGFE("Call js callback %{public}s failed, jsCallbackRef is null!", callbackType.c_str());
488             return;
489         }
490         auto method = jsCallbackRef->GetNapiValue();
491         if (method == nullptr) {
492             WLOGFE("Call js callback %{public}s failed, method is null!", callbackType.c_str());
493             return;
494         }
495         auto screenSession = screenSessionWeak.promote();
496         if (screenSession == nullptr) {
497             WLOGFE("Call js callback %{public}s failed, screenSession is null!", callbackType.c_str());
498             return;
499         }
500         napi_value propertyChangeReason = CreateJsValue(env, static_cast<int32_t>(reason));
501         napi_value argv[] = { JsScreenUtils::CreateJsScreenProperty(env, newProperty), propertyChangeReason };
502         napi_call_function(env, NapiGetUndefined(env), method, ArraySize(argv), argv, nullptr);
503     };
504 
505     if (env_ != nullptr) {
506         napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate);
507         if (ret != napi_status::napi_ok) {
508             WLOGFE("OnPropertyChange: Failed to SendEvent.");
509         }
510     } else {
511         WLOGFE("OnPropertyChange: env is nullptr");
512     }
513 }
514 
OnScreenDensityChange()515 void JsScreenSession::OnScreenDensityChange()
516 {
517     WLOGD("Call js callback: screenDensityChange.");
518     if (mCallback_.count(ON_SCREEN_DENSITY_CHANGE) == 0) {
519         WLOGFE("Callback screenDensityChange is unregistered!");
520         return;
521     }
522 
523     auto jsCallbackRef = mCallback_[ON_SCREEN_DENSITY_CHANGE];
524     wptr<ScreenSession> screenSessionWeak(screenSession_);
525     auto complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
526         [jsCallbackRef, screenSessionWeak](
527             napi_env env, NapiAsyncTask& task, int32_t status) {
528             if (jsCallbackRef == nullptr) {
529                 WLOGFE("Call js callback screenDensityChange failed, jsCallbackRef is null!");
530                 return;
531             }
532             auto method = jsCallbackRef->GetNapiValue();
533             if (method == nullptr) {
534                 WLOGFE("Call js callback screenDensityChange failed, method is null!");
535                 return;
536             }
537             auto screenSession = screenSessionWeak.promote();
538             if (screenSession == nullptr) {
539                 WLOGFE("Call js callback screenDensityChange failed, screenSession is null!");
540                 return;
541             }
542             napi_value argv[] = {};
543             napi_call_function(env, NapiGetUndefined(env), method, 0, argv, nullptr);
544         });
545 
546     napi_ref callback = nullptr;
547     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
548     NapiAsyncTask::Schedule("JsScreenSession::screenDensityChange", env_,
549         std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
550 }
551 
OnPowerStatusChange(DisplayPowerEvent event,EventStatus eventStatus,PowerStateChangeReason reason)552 void JsScreenSession::OnPowerStatusChange(DisplayPowerEvent event, EventStatus eventStatus,
553     PowerStateChangeReason reason)
554 {
555     const std::string callbackType = ON_POWER_STATUS_CHANGE_CALLBACK;
556     WLOGD("[UL_POWER]%{public}s.", callbackType.c_str());
557     if (mCallback_.count(callbackType) == 0) {
558         WLOGFW("[UL_POWER]%{public}s is unregistered!", callbackType.c_str());
559         return;
560     }
561     auto jsCallbackRef = mCallback_[callbackType];
562     wptr<ScreenSession> screenSessionWeak(screenSession_);
563     auto asyncTask = [jsCallbackRef, callbackType, screenSessionWeak, event, eventStatus, reason, env = env_]() {
564         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "jsScreenSession::OnPowerStatusChange");
565         if (jsCallbackRef == nullptr) {
566             WLOGFE("[UL_POWER]%{public}s failed, jsCallbackRef is null!", callbackType.c_str());
567             return;
568         }
569         auto method = jsCallbackRef->GetNapiValue();
570         if (method == nullptr) {
571             WLOGFE("[UL_POWER]%{public}s failed, method is null!", callbackType.c_str());
572             return;
573         }
574         auto screenSession = screenSessionWeak.promote();
575         if (screenSession == nullptr) {
576             WLOGFE("[UL_POWER]%{public}s failed, screenSession is null!", callbackType.c_str());
577             return;
578         }
579         napi_value displayPowerEvent = CreateJsValue(env, static_cast<int32_t>(event));
580         napi_value powerEventStatus = CreateJsValue(env, static_cast<int32_t>(eventStatus));
581         napi_value powerStateChangeReason = CreateJsValue(env, static_cast<int32_t>(reason));
582         napi_value argv[] = { displayPowerEvent, powerEventStatus, powerStateChangeReason };
583         napi_call_function(env, NapiGetUndefined(env), method, ArraySize(argv), argv, nullptr);
584     };
585 
586     if (env_ != nullptr) {
587         napi_status ret = napi_send_event(env_, asyncTask, napi_eprio_vip);
588         if (ret != napi_status::napi_ok) {
589             WLOGFE("OnPowerStatusChange: Failed to SendEvent.");
590         } else {
591             WLOGFI("OnPowerStatusChange: Sucess to SendEvent.");
592         }
593     } else {
594         WLOGFE("OnPowerStatusChange: env is nullptr");
595     }
596 }
597 
OnScreenRotationLockedChange(bool isLocked,ScreenId screenId)598 void JsScreenSession::OnScreenRotationLockedChange(bool isLocked, ScreenId screenId)
599 {
600     const std::string callbackType = ON_SCREEN_ROTATION_LOCKED_CHANGE;
601     WLOGD("Call js callback: %{public}s isLocked:%{public}u.", callbackType.c_str(), isLocked);
602     if (mCallback_.count(callbackType) == 0) {
603         WLOGFE("Callback %{public}s is unregistered!", callbackType.c_str());
604         return;
605     }
606 
607     auto jsCallbackRef = mCallback_[callbackType];
608     auto complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
609         [jsCallbackRef, callbackType, isLocked](napi_env env, NapiAsyncTask& task, int32_t status) {
610             if (jsCallbackRef == nullptr) {
611                 WLOGFE("Call js callback %{public}s failed, jsCallbackRef is null!", callbackType.c_str());
612                 return;
613             }
614             auto method = jsCallbackRef->GetNapiValue();
615             if (method == nullptr) {
616                 WLOGFE("Call js callback %{public}s failed, method is null!", callbackType.c_str());
617                 return;
618             }
619             napi_value argv[] = { CreateJsValue(env, isLocked) };
620             napi_call_function(env, NapiGetUndefined(env), method, ArraySize(argv), argv, nullptr);
621         });
622 
623     napi_ref callback = nullptr;
624     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
625     NapiAsyncTask::Schedule("JsScreenSession::" + callbackType, env_,
626         std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
627 }
628 
OnHoverStatusChange(int32_t hoverStatus,ScreenId screenId)629 void JsScreenSession::OnHoverStatusChange(int32_t hoverStatus, ScreenId screenId)
630 {
631     const std::string callbackType = ON_HOVER_STATUS_CHANGE_CALLBACK;
632     WLOGI("Call js callback: %{public}s.", callbackType.c_str());
633     if (mCallback_.count(callbackType) == 0) {
634         WLOGFE("Callback %{public}s is unregistered!", callbackType.c_str());
635         return;
636     }
637 
638     auto jsCallbackRef = mCallback_[callbackType];
639     wptr<ScreenSession> screenSessionWeak(screenSession_);
640     auto napiTask = [jsCallbackRef, callbackType, screenSessionWeak, hoverStatus, env = env_]() {
641         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "jsScreenSession::OnHoverStatusChange");
642         if (jsCallbackRef == nullptr) {
643             WLOGFE("Call js callback %{public}s failed, jsCallbackRef is null!", callbackType.c_str());
644             return;
645         }
646         auto method = jsCallbackRef->GetNapiValue();
647         if (method == nullptr) {
648             WLOGFE("Call js callback %{public}s failed, method is null!", callbackType.c_str());
649             return;
650         }
651         auto screenSession = screenSessionWeak.promote();
652         if (screenSession == nullptr) {
653             WLOGFE("Call js callback %{public}s failed, screenSession is null!", callbackType.c_str());
654             return;
655         }
656         napi_value argv[] = { CreateJsValue(env, hoverStatus) };
657         napi_call_function(env, NapiGetUndefined(env), method, ArraySize(argv), argv, nullptr);
658     };
659     if (env_ != nullptr) {
660         napi_status ret = napi_send_event(env_, napiTask, napi_eprio_immediate);
661         if (ret != napi_status::napi_ok) {
662             WLOGFE("OnHoverStatusChange: Failed to SendEvent.");
663         }
664     } else {
665         WLOGFE("OnHoverStatusChange: env is nullptr");
666     }
667 }
668 
OnScreenCaptureNotify(ScreenId mainScreenId,int32_t uid,const std::string & clientName)669 void JsScreenSession::OnScreenCaptureNotify(ScreenId mainScreenId, int32_t uid, const std::string& clientName)
670 {
671     const std::string callbackType = ON_SCREEN_CAPTURE_NOTIFY;
672     if (mCallback_.count(callbackType) == 0) {
673         WLOGFW("Callback is unregistered!");
674         return;
675     }
676     auto jsCallbackRef = mCallback_[callbackType];
677     auto asyncTask = [jsCallbackRef, callbackType, mainScreenId, uid, clientName, env = env_]() {
678         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "jsScreenSession::OnScreenCaptureNotify");
679         if (jsCallbackRef == nullptr) {
680             WLOGFE("Call js callback failed, jsCallbackRef is null!");
681             return;
682         }
683         auto method = jsCallbackRef->GetNapiValue();
684         if (method == nullptr) {
685             WLOGFE("Call js callback failed, method is null!");
686             return;
687         }
688         napi_value mainId = CreateJsValue(env, static_cast<int64_t>(mainScreenId));
689         napi_value clientUid = CreateJsValue(env, uid);
690         napi_value client = CreateJsValue(env, clientName);
691         napi_value argv[] = { mainId, clientUid, client };
692         napi_call_function(env, NapiGetUndefined(env), method, ArraySize(argv), argv, nullptr);
693     };
694     if (env_ != nullptr) {
695         napi_status ret = napi_send_event(env_, asyncTask, napi_eprio_immediate);
696         if (ret != napi_status::napi_ok) {
697             WLOGFE("OnScreenCaptureNotify: Failed to SendEvent.");
698         }
699     } else {
700         WLOGFE("OnScreenCaptureNotify: env is nullptr");
701     }
702 }
703 } // namespace OHOS::Rosen
704