• 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_screen.h"
17 
18 #include <cinttypes>
19 #include <hitrace_meter.h>
20 
21 #include "screen.h"
22 #include "screen_info.h"
23 #include "window_manager_hilog.h"
24 #ifdef XPOWER_EVENT_ENABLE
25 #include "xpower_event_js.h"
26 #endif // XPOWER_EVENT_ENABLE
27 
28 namespace OHOS {
29 namespace Rosen {
30 using namespace AbilityRuntime;
31 constexpr size_t ARGC_ONE = 1;
32 constexpr size_t ARGC_TWO = 2;
33 
34 static thread_local std::map<ScreenId, std::shared_ptr<NativeReference>> g_JsScreenMap;
35 std::recursive_mutex g_mutex;
36 
JsScreen(const sptr<Screen> & screen)37 JsScreen::JsScreen(const sptr<Screen>& screen) : screen_(screen)
38 {
39 }
40 
~JsScreen()41 JsScreen::~JsScreen()
42 {
43     TLOGI(WmsLogTag::DMS, "JsScreen::~JsScreen is called");
44 }
45 
Finalizer(napi_env env,void * data,void * hint)46 void JsScreen::Finalizer(napi_env env, void* data, void* hint)
47 {
48     TLOGI(WmsLogTag::DMS, "called");
49     auto jsScreen = std::unique_ptr<JsScreen>(static_cast<JsScreen*>(data));
50     if (jsScreen == nullptr) {
51         TLOGE(WmsLogTag::DMS, "jsScreen is null");
52         return;
53     }
54     sptr<Screen> screen = jsScreen->screen_;
55     if (screen == nullptr) {
56         TLOGE(WmsLogTag::DMS, "screen is null");
57         return;
58     }
59     ScreenId screenId = screen->GetId();
60     TLOGI(WmsLogTag::DMS, "screenId : %{public}" PRIu64"", screenId);
61     std::lock_guard<std::recursive_mutex> lock(g_mutex);
62     if (g_JsScreenMap.find(screenId) != g_JsScreenMap.end()) {
63         TLOGI(WmsLogTag::DMS, "screen is destroyed: %{public}" PRIu64"", screenId);
64         g_JsScreenMap.erase(screenId);
65     }
66 }
67 
SetOrientation(napi_env env,napi_callback_info info)68 napi_value JsScreen::SetOrientation(napi_env env, napi_callback_info info)
69 {
70     JsScreen* me = CheckParamsAndGetThis<JsScreen>(env, info);
71     return (me != nullptr) ? me->OnSetOrientation(env, info) : nullptr;
72 }
73 
NapiGetUndefined(napi_env env)74 napi_value NapiGetUndefined(napi_env env)
75 {
76     napi_value result = nullptr;
77     napi_get_undefined(env, &result);
78     return result;
79 }
80 
GetType(napi_env env,napi_value value)81 napi_valuetype GetType(napi_env env, napi_value value)
82 {
83     napi_valuetype res = napi_undefined;
84     napi_typeof(env, value, &res);
85     return res;
86 }
87 
OnSetOrientation(napi_env env,napi_callback_info info)88 napi_value JsScreen::OnSetOrientation(napi_env env, napi_callback_info info)
89 {
90     TLOGI(WmsLogTag::DMS, "called");
91     bool paramValidFlag = true;
92     Orientation orientation = Orientation::UNSPECIFIED;
93     size_t argc = 4;
94     napi_value argv[4] = {nullptr};
95     std::string errMsg = "";
96     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
97     if (argc < ARGC_ONE) {
98         TLOGE(WmsLogTag::DMS, "OnSetOrientation Params not match, info argc: %{public}zu", argc);
99         errMsg = "Invalid args count, need one arg at least!";
100         paramValidFlag = false;
101     } else if (!ConvertFromJsValue(env, argv[0], orientation)) {
102         paramValidFlag = false;
103         TLOGE(WmsLogTag::DMS, "Failed to convert parameter to orientation");
104         errMsg = "Failed to convert parameter to orientation";
105     }
106     if (!paramValidFlag) {
107         TLOGE(WmsLogTag::DMS, "OnSetOrientation paramValidFlag error");
108         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM), errMsg));
109         return NapiGetUndefined(env);
110     }
111     if (orientation < Orientation::BEGIN || orientation > Orientation::END) {
112         TLOGE(WmsLogTag::DMS, "Orientation param error! orientation value must from enum Orientation");
113         errMsg = "orientation value must from enum Orientation";
114         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM), errMsg));
115         return NapiGetUndefined(env);
116     }
117     napi_value lastParam = nullptr;
118     if (argc >= ARGC_TWO && argv[ARGC_TWO - 1] != nullptr &&
119         GetType(env, argv[ARGC_TWO - 1]) == napi_function) {
120         lastParam = argv[ARGC_TWO - 1];
121     }
122     napi_value result = nullptr;
123     std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
124     auto asyncTask = [this, orientation, env, task = napiAsyncTask.get()]() {
125         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreen::OnSetOrientation");
126         DmErrorCode ret = DM_JS_TO_ERROR_CODE_MAP.at(screen_->SetOrientation(orientation));
127         if (ret == DmErrorCode::DM_OK) {
128             task->Resolve(env, NapiGetUndefined(env));
129             TLOGNI(WmsLogTag::DMS, "OnSetOrientation success");
130         } else {
131             task->Reject(env, CreateJsError(env, static_cast<int32_t>(ret), "JsScreen::OnSetOrientation failed."));
132             TLOGNE(WmsLogTag::DMS, "OnSetOrientation failed");
133         }
134         delete task;
135     };
136     NapiSendDmsEvent(env, asyncTask, napiAsyncTask, "OnSetOrientation");
137     return result;
138 }
139 
SetScreenActiveMode(napi_env env,napi_callback_info info)140 napi_value JsScreen::SetScreenActiveMode(napi_env env, napi_callback_info info)
141 {
142     TLOGI(WmsLogTag::DMS, "called");
143     JsScreen* me = CheckParamsAndGetThis<JsScreen>(env, info);
144 #ifdef XPOWER_EVENT_ENABLE
145     if (me != nullptr) {
146         HiviewDFX::ReportXPowerJsStackSysEvent(env, "EPS_LCD_FREQ");
147     }
148 #endif // XPOWER_EVENT_ENABLE
149     return (me != nullptr) ? me->OnSetScreenActiveMode(env, info) : nullptr;
150 }
151 
OnSetScreenActiveMode(napi_env env,napi_callback_info info)152 napi_value JsScreen::OnSetScreenActiveMode(napi_env env, napi_callback_info info)
153 {
154     TLOGI(WmsLogTag::DMS, "called");
155     bool paramValidFlag = true;
156     uint32_t modeId = 0;
157     size_t argc = 4;
158     napi_value argv[4] = {nullptr};
159     std::string errMsg = "";
160     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
161     if (argc < ARGC_ONE) {
162         TLOGE(WmsLogTag::DMS, "OnSetScreenActiveMode Params not match %{public}zu", argc);
163         errMsg = "Invalid args count, need one arg at least!";
164         paramValidFlag = false;
165     } else {
166         if (!ConvertFromJsValue(env, argv[0], modeId)) {
167             TLOGE(WmsLogTag::DMS, "Failed to convert parameter to modeId");
168             errMsg = "Failed to convert parameter to modeId";
169             paramValidFlag = false;
170         }
171     }
172     if (!paramValidFlag) {
173         TLOGE(WmsLogTag::DMS, "OnSetScreenActiveMode paramValidFlag error");
174         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM), errMsg));
175         return NapiGetUndefined(env);
176     }
177     napi_value lastParam = nullptr;
178     if (argc >= ARGC_TWO && argv[ARGC_TWO - 1] != nullptr &&
179         GetType(env, argv[ARGC_TWO - 1]) == napi_function) {
180         lastParam = argv[ARGC_TWO - 1];
181     }
182     napi_value result = nullptr;
183     std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
184     auto asyncTask = [this, modeId, env, task = napiAsyncTask.get()]() {
185         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreen::OnSetScreenActiveMode");
186         DmErrorCode ret = DM_JS_TO_ERROR_CODE_MAP.at(screen_->SetScreenActiveMode(modeId));
187         if (ret == DmErrorCode::DM_OK) {
188             task->Resolve(env, NapiGetUndefined(env));
189             TLOGNI(WmsLogTag::DMS, "OnSetScreenActiveMode success");
190         } else {
191             task->Reject(env, CreateJsError(env, static_cast<int32_t>(ret),
192                                             "JsScreen::OnSetScreenActiveMode failed."));
193             TLOGNE(WmsLogTag::DMS, "OnSetScreenActiveMode failed");
194         }
195         delete task;
196     };
197     NapiSendDmsEvent(env, asyncTask, napiAsyncTask, "OnSetScreenActiveMode");
198     return result;
199 }
200 
SetDensityDpi(napi_env env,napi_callback_info info)201 napi_value JsScreen::SetDensityDpi(napi_env env, napi_callback_info info)
202 {
203     TLOGI(WmsLogTag::DMS, "called");
204     JsScreen* me = CheckParamsAndGetThis<JsScreen>(env, info);
205     return (me != nullptr) ? me->OnSetDensityDpi(env, info) : nullptr;
206 }
207 
OnSetDensityDpi(napi_env env,napi_callback_info info)208 napi_value JsScreen::OnSetDensityDpi(napi_env env, napi_callback_info info)
209 {
210     TLOGI(WmsLogTag::DMS, "called");
211     bool paramValidFlag = true;
212     uint32_t densityDpi = 0;
213     size_t argc = 4;
214     std::string errMsg = "";
215     napi_value argv[4] = {nullptr};
216     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
217     if (argc < ARGC_ONE) {
218         TLOGE(WmsLogTag::DMS, "OnSetDensityDpi Params not match %{public}zu", argc);
219         errMsg = "Invalid args count, need one arg at least!";
220         paramValidFlag = false;
221     } else {
222         if (!ConvertFromJsValue(env, argv[0], densityDpi)) {
223             TLOGE(WmsLogTag::DMS, "Failed to convert parameter to densityDpi");
224             errMsg = "Failed to convert parameter to densityDpi";
225             paramValidFlag = false;
226         }
227     }
228     if (!paramValidFlag) {
229         TLOGE(WmsLogTag::DMS, "OnSetDensityDpi paramValidFlag error");
230         napi_throw(env, CreateJsError(env, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM), errMsg));
231         return NapiGetUndefined(env);
232     }
233     napi_value lastParam = nullptr;
234     if (argc >= ARGC_TWO && argv[ARGC_TWO - 1] != nullptr &&
235         GetType(env, argv[ARGC_TWO - 1]) == napi_function) {
236         lastParam = argv[ARGC_TWO - 1];
237     }
238     napi_value result = nullptr;
239     std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
240     auto asyncTask = [this, densityDpi, env, task = napiAsyncTask.get()]() {
241         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "JsScreen::OnSetDensityDpi");
242         DmErrorCode ret = DM_JS_TO_ERROR_CODE_MAP.at(screen_->SetDensityDpi(densityDpi));
243         if (ret == DmErrorCode::DM_OK) {
244             task->Resolve(env, NapiGetUndefined(env));
245             TLOGNI(WmsLogTag::DMS, "OnSetDensityDpi success");
246         } else {
247             task->Reject(env, CreateJsError(env, static_cast<int32_t>(ret),
248                                             "JsScreen::OnSetDensityDpi failed."));
249             TLOGNE(WmsLogTag::DMS, "OnSetDensityDpi failed");
250         }
251         delete task;
252     };
253     NapiSendDmsEvent(env, asyncTask, napiAsyncTask, "OnSetDensityDpi");
254     return result;
255 }
256 
NapiSendDmsEvent(napi_env env,std::function<void ()> asyncTask,std::unique_ptr<AbilityRuntime::NapiAsyncTask> & napiAsyncTask,const std::string & taskName)257 void JsScreen::NapiSendDmsEvent(napi_env env, std::function<void()> asyncTask,
258     std::unique_ptr<AbilityRuntime::NapiAsyncTask>& napiAsyncTask, const std::string& taskName)
259 {
260     if (napi_send_event(env, asyncTask, napi_eprio_immediate, taskName.c_str()) != napi_status::napi_ok) {
261         napiAsyncTask->Reject(env, CreateJsError(env,
262                 static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_SCREEN), "Send event failed!"));
263     } else {
264         napiAsyncTask.release();
265         TLOGE(WmsLogTag::DMS, "send event success");
266     }
267 }
268 
FindJsDisplayObject(ScreenId screenId)269 std::shared_ptr<NativeReference> FindJsDisplayObject(ScreenId screenId)
270 {
271     TLOGD(WmsLogTag::DMS, "[NAPI]Try to find screen %{public}" PRIu64" in g_JsScreenMap", screenId);
272     std::lock_guard<std::recursive_mutex> lock(g_mutex);
273     if (g_JsScreenMap.find(screenId) == g_JsScreenMap.end()) {
274         TLOGI(WmsLogTag::DMS, "[NAPI]Can not find screen %{public}" PRIu64" in g_JsScreenMap", screenId);
275         return nullptr;
276     }
277     return g_JsScreenMap[screenId];
278 }
279 
CreateJsScreenObject(napi_env env,sptr<Screen> & screen)280 napi_value CreateJsScreenObject(napi_env env, sptr<Screen>& screen)
281 {
282     TLOGD(WmsLogTag::DMS, "called");
283     napi_value objValue = nullptr;
284     std::shared_ptr<NativeReference> jsScreenObj = FindJsDisplayObject(screen->GetId());
285     if (jsScreenObj != nullptr && jsScreenObj->GetNapiValue() != nullptr) {
286         TLOGI(WmsLogTag::DMS, "[NAPI]FindJsScreenObject %{public}" PRIu64"", screen->GetId());
287         objValue = jsScreenObj->GetNapiValue();
288     }
289     if (objValue == nullptr) {
290         napi_create_object(env, &objValue);
291     }
292     if (objValue == nullptr) {
293         TLOGE(WmsLogTag::DMS, "Failed to convert prop to jsObject");
294         return NapiGetUndefined(env);
295     }
296     std::unique_ptr<JsScreen> jsScreen = std::make_unique<JsScreen>(screen);
297     napi_wrap(env, objValue, jsScreen.release(), JsScreen::Finalizer, nullptr, nullptr);
298     auto info = screen->GetScreenInfo();
299     if (info == nullptr) {
300         TLOGE(WmsLogTag::DMS, "Failed to GetScreenInfo");
301         return NapiGetUndefined(env);
302     }
303     ScreenId screenId = info->GetScreenId();
304     napi_set_named_property(env, objValue, "id",
305         CreateJsValue(env, screenId == SCREEN_ID_INVALID ? -1 : static_cast<int64_t>(screenId)));
306     ScreenId rsId = info->GetRsId();
307     napi_set_named_property(env, objValue, "rsId",
308         CreateJsValue(env, screenId == SCREEN_ID_INVALID ? -1 : static_cast<int64_t>(rsId)));
309     ScreenId parentId = info->GetParentId();
310     napi_set_named_property(env, objValue, "parent",
311         CreateJsValue(env, parentId == SCREEN_ID_INVALID ? -1 : static_cast<int64_t>(parentId)));
312     napi_set_named_property(env, objValue, "orientation", CreateJsValue(env, info->GetOrientation()));
313     napi_set_named_property(env, objValue, "serialNumber", CreateJsValue(env, info->GetSerialNumber()));
314     napi_set_named_property(env, objValue, "sourceMode", CreateJsValue(env, info->GetSourceMode()));
315     napi_set_named_property(env, objValue, "activeModeIndex", CreateJsValue(env, info->GetModeId()));
316     napi_set_named_property(env, objValue, "supportedModeInfo", CreateJsScreenModeArrayObject(env, info->GetModes()));
317     napi_set_named_property(env, objValue, "densityDpi", CreateJsValue(env,
318         static_cast<uint32_t>(info->GetVirtualPixelRatio() * DOT_PER_INCH))); // Dpi = Density(VPR) * 160.
319     if (jsScreenObj == nullptr || jsScreenObj->GetNapiValue() == nullptr) {
320         std::shared_ptr<NativeReference> JsScreenRef;
321         napi_ref result = nullptr;
322         napi_create_reference(env, objValue, 1, &result);
323         JsScreenRef.reset(reinterpret_cast<NativeReference*>(result));
324         std::lock_guard<std::recursive_mutex> lock(g_mutex);
325         g_JsScreenMap[screenId] = JsScreenRef;
326         const char *moduleName = "JsScreen";
327         BindNativeFunction(env, objValue, "setScreenActiveMode", moduleName, JsScreen::SetScreenActiveMode);
328         BindNativeFunction(env, objValue, "setOrientation", moduleName, JsScreen::SetOrientation);
329         BindNativeFunction(env, objValue, "setDensityDpi", moduleName, JsScreen::SetDensityDpi);
330     }
331     return objValue;
332 }
333 
CreateJsScreenModeArrayObject(napi_env env,std::vector<sptr<SupportedScreenModes>> screenModes)334 napi_value CreateJsScreenModeArrayObject(napi_env env, std::vector<sptr<SupportedScreenModes>> screenModes)
335 {
336     napi_value arrayValue = nullptr;
337     napi_create_array_with_length(env, screenModes.size(), &arrayValue);
338     size_t i = 0;
339     for (const auto& mode : screenModes) {
340         napi_set_element(env, arrayValue, i++, CreateJsScreenModeObject(env, mode));
341     }
342     return arrayValue;
343 }
344 
CreateJsScreenModeObject(napi_env env,const sptr<SupportedScreenModes> & mode)345 napi_value CreateJsScreenModeObject(napi_env env, const sptr<SupportedScreenModes>& mode)
346 {
347     TLOGD(WmsLogTag::DMS, "called");
348     napi_value objValue = nullptr;
349     napi_create_object(env, &objValue);
350     if (objValue == nullptr) {
351         TLOGE(WmsLogTag::DMS, "Failed to convert prop to jsObject");
352         return NapiGetUndefined(env);
353     }
354     uint32_t id = mode->id_;
355     uint32_t width = mode->width_;
356     uint32_t height = mode->height_;
357     uint32_t refreshRate = mode->refreshRate_;
358     napi_set_named_property(env, objValue, "id", CreateJsValue(env, id));
359     napi_set_named_property(env, objValue, "width", CreateJsValue(env, width));
360     napi_set_named_property(env, objValue, "height", CreateJsValue(env, height));
361     napi_set_named_property(env, objValue, "refreshRate", CreateJsValue(env, refreshRate));
362     return objValue;
363 }
364 }  // namespace Rosen
365 }  // namespace OHOS
366