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 "screen.h"
20 #include "screen_info.h"
21 #include "window_manager_hilog.h"
22
23 namespace OHOS {
24 namespace Rosen {
25 using namespace AbilityRuntime;
26 constexpr size_t ARGC_ONE = 1;
27 constexpr size_t ARGC_TWO = 2;
28 namespace {
29 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "JsScreen"};
30 }
31
32 static thread_local std::map<ScreenId, std::shared_ptr<NativeReference>> g_JsScreenMap;
33 std::recursive_mutex g_mutex;
34
JsScreen(const sptr<Screen> & screen)35 JsScreen::JsScreen(const sptr<Screen>& screen) : screen_(screen)
36 {
37 }
38
~JsScreen()39 JsScreen::~JsScreen()
40 {
41 WLOGFI("JsScreen::~JsScreen is called");
42 }
43
Finalizer(NativeEngine * engine,void * data,void * hint)44 void JsScreen::Finalizer(NativeEngine* engine, void* data, void* hint)
45 {
46 WLOGFI("JsScreen::Finalizer is called");
47 auto jsScreen = std::unique_ptr<JsScreen>(static_cast<JsScreen*>(data));
48 if (jsScreen == nullptr) {
49 WLOGFE("jsScreen::Finalizer jsScreen is null");
50 return;
51 }
52 sptr<Screen> screen = jsScreen->screen_;
53 if (screen == nullptr) {
54 WLOGFE("JsScreen::Finalizer screen is null");
55 return;
56 }
57 ScreenId screenId = screen->GetId();
58 WLOGFI("JsScreen::Finalizer screenId : %{public}" PRIu64"", screenId);
59 std::lock_guard<std::recursive_mutex> lock(g_mutex);
60 if (g_JsScreenMap.find(screenId) != g_JsScreenMap.end()) {
61 WLOGFI("JsScreen::Finalizer screen is destroyed: %{public}" PRIu64"", screenId);
62 g_JsScreenMap.erase(screenId);
63 }
64 }
65
SetOrientation(NativeEngine * engine,NativeCallbackInfo * info)66 NativeValue* JsScreen::SetOrientation(NativeEngine* engine, NativeCallbackInfo* info)
67 {
68 JsScreen* me = CheckParamsAndGetThis<JsScreen>(engine, info);
69 return (me != nullptr) ? me->OnSetOrientation(*engine, *info) : nullptr;
70 }
71
OnSetOrientation(NativeEngine & engine,NativeCallbackInfo & info)72 NativeValue* JsScreen::OnSetOrientation(NativeEngine& engine, NativeCallbackInfo& info)
73 {
74 WLOGFI("OnSetOrientation is called");
75 bool paramValidFlag = true;
76 Orientation orientation = Orientation::UNSPECIFIED;
77 if (info.argc < ARGC_ONE) {
78 WLOGFE("OnSetOrientation Params not match, info argc: %{public}zu", info.argc);
79 paramValidFlag = false;
80 } else {
81 if (!ConvertFromJsValue(engine, info.argv[0], orientation)) {
82 paramValidFlag = false;
83 WLOGFE("Failed to convert parameter to orientation");
84 }
85 }
86 if (!paramValidFlag) {
87 WLOGE("OnSetOrientation paramValidFlag error");
88 engine.Throw(CreateJsError(engine, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
89 return engine.CreateUndefined();
90 }
91 if (orientation < Orientation::BEGIN || orientation > Orientation::END) {
92 WLOGE("Orientation param error! orientation value must from enum Orientation");
93 engine.Throw(CreateJsError(engine, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
94 return engine.CreateUndefined();
95 }
96
97 AsyncTask::CompleteCallback complete =
98 [=](NativeEngine& engine, AsyncTask& task, int32_t status) {
99 bool res = screen_->SetOrientation(orientation);
100 if (res) {
101 task.Resolve(engine, engine.CreateUndefined());
102 WLOGFI("OnSetOrientation success");
103 } else {
104 task.Reject(engine, CreateJsError(engine, static_cast<int32_t>(DmErrorCode::DM_ERROR_SYSTEM_INNORMAL),
105 "JsScreen::OnSetOrientation failed."));
106 WLOGFE("OnSetOrientation failed");
107 }
108 };
109 NativeValue* lastParam = nullptr;
110 if (info.argc >= ARGC_TWO && info.argv[ARGC_TWO - 1] != nullptr &&
111 info.argv[ARGC_TWO - 1]->TypeOf() == NATIVE_FUNCTION) {
112 lastParam = info.argv[ARGC_TWO - 1];
113 }
114 NativeValue* result = nullptr;
115 AsyncTask::Schedule("JsScreen::OnSetOrientation",
116 engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
117 return result;
118 }
119
120
SetScreenActiveMode(NativeEngine * engine,NativeCallbackInfo * info)121 NativeValue* JsScreen::SetScreenActiveMode(NativeEngine* engine, NativeCallbackInfo* info)
122 {
123 WLOGFI("SetScreenActiveMode is called");
124 JsScreen* me = CheckParamsAndGetThis<JsScreen>(engine, info);
125 return (me != nullptr) ? me->OnSetScreenActiveMode(*engine, *info) : nullptr;
126 }
127
OnSetScreenActiveMode(NativeEngine & engine,NativeCallbackInfo & info)128 NativeValue* JsScreen::OnSetScreenActiveMode(NativeEngine& engine, NativeCallbackInfo& info)
129 {
130 WLOGFI("OnSetScreenActiveMode is called");
131 bool paramValidFlag = true;
132 uint32_t modeId = 0;
133 if (info.argc < ARGC_ONE) {
134 WLOGFE("OnSetScreenActiveMode Params not match %{public}zu", info.argc);
135 paramValidFlag = false;
136 } else {
137 if (!ConvertFromJsValue(engine, info.argv[0], modeId)) {
138 WLOGFE("Failed to convert parameter to modeId");
139 paramValidFlag = false;
140 }
141 }
142 if (!paramValidFlag) {
143 WLOGFE("OnSetScreenActiveMode paramValidFlag error");
144 engine.Throw(CreateJsError(engine, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
145 return engine.CreateUndefined();
146 }
147
148 AsyncTask::CompleteCallback complete =
149 [=](NativeEngine& engine, AsyncTask& task, int32_t status) {
150 bool res = screen_->SetScreenActiveMode(modeId);
151 if (res) {
152 task.Resolve(engine, engine.CreateUndefined());
153 WLOGFI("OnSetScreenActiveMode success");
154 } else {
155 task.Reject(engine, CreateJsError(engine, static_cast<int32_t>(DmErrorCode::DM_ERROR_SYSTEM_INNORMAL),
156 "JsScreen::OnSetScreenActiveMode failed."));
157 WLOGFE("OnSetScreenActiveMode failed");
158 }
159 };
160 NativeValue* lastParam = nullptr;
161 if (info.argc >= ARGC_TWO && info.argv[ARGC_TWO - 1] != nullptr &&
162 info.argv[ARGC_TWO - 1]->TypeOf() == NATIVE_FUNCTION) {
163 lastParam = info.argv[ARGC_TWO - 1];
164 }
165 NativeValue* result = nullptr;
166 AsyncTask::Schedule("JsScreen::OnSetScreenActiveMode",
167 engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
168 return result;
169 }
170
SetDensityDpi(NativeEngine * engine,NativeCallbackInfo * info)171 NativeValue* JsScreen::SetDensityDpi(NativeEngine* engine, NativeCallbackInfo* info)
172 {
173 WLOGFI("SetDensityDpi is called");
174 JsScreen* me = CheckParamsAndGetThis<JsScreen>(engine, info);
175 return (me != nullptr) ? me->OnSetDensityDpi(*engine, *info) : nullptr;
176 }
177
OnSetDensityDpi(NativeEngine & engine,NativeCallbackInfo & info)178 NativeValue* JsScreen::OnSetDensityDpi(NativeEngine& engine, NativeCallbackInfo& info)
179 {
180 WLOGFI("OnSetDensityDpi is called");
181 bool paramValidFlag = true;
182 uint32_t densityDpi = 0;
183 if (info.argc < ARGC_ONE) {
184 WLOGFE("OnSetDensityDpi Params not match %{public}zu", info.argc);
185 paramValidFlag = false;
186 } else {
187 if (!ConvertFromJsValue(engine, info.argv[0], densityDpi)) {
188 WLOGFE("Failed to convert parameter to densityDpi");
189 paramValidFlag = false;
190 }
191 }
192 if (!paramValidFlag) {
193 WLOGFE("OnSetDensityDpi paramValidFlag error");
194 engine.Throw(CreateJsError(engine, static_cast<int32_t>(DmErrorCode::DM_ERROR_INVALID_PARAM)));
195 return engine.CreateUndefined();
196 }
197
198 AsyncTask::CompleteCallback complete =
199 [=](NativeEngine& engine, AsyncTask& task, int32_t status) {
200 bool res = screen_->SetDensityDpi(densityDpi);
201 if (res) {
202 task.Resolve(engine, engine.CreateUndefined());
203 WLOGFI("OnSetDensityDpi success");
204 } else {
205 task.Reject(engine, CreateJsError(engine, static_cast<int32_t>(DmErrorCode::DM_ERROR_SYSTEM_INNORMAL),
206 "JsScreen::OnSetDensityDpi failed."));
207 WLOGFE("OnSetDensityDpi failed");
208 }
209 };
210 NativeValue* lastParam = nullptr;
211 if (info.argc >= ARGC_TWO && info.argv[ARGC_TWO - 1] != nullptr &&
212 info.argv[ARGC_TWO - 1]->TypeOf() == NATIVE_FUNCTION) {
213 lastParam = info.argv[ARGC_TWO - 1];
214 }
215 NativeValue* result = nullptr;
216 AsyncTask::Schedule("JsScreen::OnSetDensityDpi",
217 engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
218 return result;
219 }
220
FindJsDisplayObject(ScreenId screenId)221 std::shared_ptr<NativeReference> FindJsDisplayObject(ScreenId screenId)
222 {
223 WLOGFI("[NAPI]Try to find screen %{public}" PRIu64" in g_JsScreenMap", screenId);
224 std::lock_guard<std::recursive_mutex> lock(g_mutex);
225 if (g_JsScreenMap.find(screenId) == g_JsScreenMap.end()) {
226 WLOGFI("[NAPI]Can not find screen %{public}" PRIu64" in g_JsScreenMap", screenId);
227 return nullptr;
228 }
229 return g_JsScreenMap[screenId];
230 }
231
CreateJsScreenObject(NativeEngine & engine,sptr<Screen> & screen)232 NativeValue* CreateJsScreenObject(NativeEngine& engine, sptr<Screen>& screen)
233 {
234 WLOGFI("JsScreen::CreateJsScreen is called");
235 NativeValue* objValue = nullptr;
236 std::shared_ptr<NativeReference> jsScreenObj = FindJsDisplayObject(screen->GetId());
237 if (jsScreenObj != nullptr && jsScreenObj->Get() != nullptr) {
238 WLOGFI("[NAPI]FindJsScreenObject %{public}" PRIu64"", screen->GetId());
239 objValue = jsScreenObj->Get();
240 }
241 if (objValue == nullptr) {
242 objValue = engine.CreateObject();
243 }
244 NativeObject* object = ConvertNativeValueTo<NativeObject>(objValue);
245 if (object == nullptr) {
246 WLOGFE("Failed to convert prop to jsObject");
247 return engine.CreateUndefined();
248 }
249 std::unique_ptr<JsScreen> jsScreen = std::make_unique<JsScreen>(screen);
250 object->SetNativePointer(jsScreen.release(), JsScreen::Finalizer, nullptr);
251 auto info = screen->GetScreenInfo();
252 if (info == nullptr) {
253 WLOGFE("Failed to GetScreenInfo");
254 return engine.CreateUndefined();
255 }
256 ScreenId screenId = info->GetScreenId();
257 object->SetProperty("id",
258 CreateJsValue(engine, screenId == SCREEN_ID_INVALID ? -1 : static_cast<int64_t>(screenId)));
259 ScreenId parentId = info->GetParentId();
260 object->SetProperty("parent",
261 CreateJsValue(engine, parentId == SCREEN_ID_INVALID ? -1 : static_cast<int64_t>(parentId)));
262 object->SetProperty("orientation", CreateJsValue(engine, info->GetOrientation()));
263 object->SetProperty("activeModeIndex", CreateJsValue(engine, info->GetModeId()));
264 object->SetProperty("supportedModeInfo", CreateJsScreenModeArrayObject(engine, info->GetModes()));
265 object->SetProperty("densityDpi", CreateJsValue(engine,
266 static_cast<uint32_t>(info->GetVirtualPixelRatio() * DOT_PER_INCH))); // Dpi = Density(VPR) * 160.
267 if (jsScreenObj == nullptr || jsScreenObj->Get() == nullptr) {
268 std::shared_ptr<NativeReference> JsScreenRef;
269 JsScreenRef.reset(engine.CreateReference(objValue, 1));
270 std::lock_guard<std::recursive_mutex> lock(g_mutex);
271 g_JsScreenMap[screenId] = JsScreenRef;
272 const char *moduleName = "JsScreen";
273 BindNativeFunction(engine, *object, "setScreenActiveMode", moduleName, JsScreen::SetScreenActiveMode);
274 BindNativeFunction(engine, *object, "setOrientation", moduleName, JsScreen::SetOrientation);
275 BindNativeFunction(engine, *object, "setDensityDpi", moduleName, JsScreen::SetDensityDpi);
276 }
277 return objValue;
278 }
279
CreateJsScreenModeArrayObject(NativeEngine & engine,std::vector<sptr<SupportedScreenModes>> screenModes)280 NativeValue* CreateJsScreenModeArrayObject(NativeEngine& engine, std::vector<sptr<SupportedScreenModes>> screenModes)
281 {
282 NativeValue* arrayValue = engine.CreateArray(screenModes.size());
283 NativeArray* array = ConvertNativeValueTo<NativeArray>(arrayValue);
284 size_t i = 0;
285 for (const auto& mode : screenModes) {
286 array->SetElement(i++, CreateJsScreenModeObject(engine, mode));
287 }
288 return arrayValue;
289 }
290
CreateJsScreenModeObject(NativeEngine & engine,const sptr<SupportedScreenModes> & mode)291 NativeValue* CreateJsScreenModeObject(NativeEngine& engine, const sptr<SupportedScreenModes>& mode)
292 {
293 WLOGFI("JsScreen::CreateJsScreenMode is called");
294 NativeValue* objValue = engine.CreateObject();
295 NativeObject* optionObject = ConvertNativeValueTo<NativeObject>(objValue);
296 if (optionObject == nullptr) {
297 WLOGFE("Failed to convert prop to jsObject");
298 return engine.CreateUndefined();
299 }
300 uint32_t width = mode->width_;
301 uint32_t height = mode->height_;
302 uint32_t refreshRate = mode->refreshRate_;
303 optionObject->SetProperty("width", CreateJsValue(engine, width));
304 optionObject->SetProperty("height", CreateJsValue(engine, height));
305 optionObject->SetProperty("refreshRate", CreateJsValue(engine, refreshRate));
306 return objValue;
307 }
308 } // namespace Rosen
309 } // namespace OHOS
310