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