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 <vector>
17 #include <new>
18
19 #include "js_runtime_utils.h"
20 #include "native_engine/native_reference.h"
21 #include "display_manager.h"
22 #include "window_manager_hilog.h"
23 #include "singleton_container.h"
24 #include "js_display_listener.h"
25 #include "js_display.h"
26 #include "js_display_manager.h"
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 constexpr int32_t INDEX_ONE = 1;
34 namespace {
35 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0, "JsDisplayManager"};
36 }
37
38 class JsDisplayManager {
39 public:
JsDisplayManager(NativeEngine * engine)40 explicit JsDisplayManager(NativeEngine* engine) {
41 }
42
43 ~JsDisplayManager() = default;
44
Finalizer(NativeEngine * engine,void * data,void * hint)45 static void Finalizer(NativeEngine* engine, void* data, void* hint)
46 {
47 WLOGFI("JsDisplayManager::Finalizer is called");
48 std::unique_ptr<JsDisplayManager>(static_cast<JsDisplayManager*>(data));
49 }
50
GetDefaultDisplay(NativeEngine * engine,NativeCallbackInfo * info)51 static NativeValue* GetDefaultDisplay(NativeEngine* engine, NativeCallbackInfo* info)
52 {
53 JsDisplayManager* me = CheckParamsAndGetThis<JsDisplayManager>(engine, info);
54 return (me != nullptr) ? me->OnGetDefaultDisplay(*engine, *info) : nullptr;
55 }
56
GetAllDisplay(NativeEngine * engine,NativeCallbackInfo * info)57 static NativeValue* GetAllDisplay(NativeEngine* engine, NativeCallbackInfo* info)
58 {
59 JsDisplayManager* me = CheckParamsAndGetThis<JsDisplayManager>(engine, info);
60 return (me != nullptr) ? me->OnGetAllDisplay(*engine, *info) : nullptr;
61 }
62
RegisterDisplayManagerCallback(NativeEngine * engine,NativeCallbackInfo * info)63 static NativeValue* RegisterDisplayManagerCallback(NativeEngine* engine, NativeCallbackInfo* info)
64 {
65 JsDisplayManager* me = CheckParamsAndGetThis<JsDisplayManager>(engine, info);
66 return (me != nullptr) ? me->OnRegisterDisplayManagerCallback(*engine, *info) : nullptr;
67 }
68
UnregisterDisplayManagerCallback(NativeEngine * engine,NativeCallbackInfo * info)69 static NativeValue* UnregisterDisplayManagerCallback(NativeEngine* engine, NativeCallbackInfo* info)
70 {
71 JsDisplayManager* me = CheckParamsAndGetThis<JsDisplayManager>(engine, info);
72 return (me != nullptr) ? me->OnUnregisterDisplayManagerCallback(*engine, *info) : nullptr;
73 }
74
75 private:
76 std::map<std::string, std::map<std::unique_ptr<NativeReference>, sptr<JsDisplayListener>>> jsCbMap_;
77 std::mutex mtx_;
78
OnGetDefaultDisplay(NativeEngine & engine,NativeCallbackInfo & info)79 NativeValue* OnGetDefaultDisplay(NativeEngine& engine, NativeCallbackInfo& info)
80 {
81 WLOGFI("JsDisplayManager::OnGetDefaultDisplay is called");
82 DMError errCode = DMError::DM_OK;
83 if (info.argc != 0 && info.argc != ARGC_ONE) {
84 WLOGFE("JsDisplayManager::OnGetDefaultDisplay params not match");
85 errCode = DMError::DM_ERROR_INVALID_PARAM;
86 }
87
88 AsyncTask::CompleteCallback complete =
89 [=](NativeEngine& engine, AsyncTask& task, int32_t status) {
90 if (errCode != DMError::DM_OK) {
91 task.Reject(engine, CreateJsError(engine,
92 static_cast<int32_t>(errCode), "JsDisplayManager::OnGetDefaultDisplay failed."));
93 }
94 sptr<Display> display = SingletonContainer::Get<DisplayManager>().GetDefaultDisplay();
95 if (display != nullptr) {
96 task.Resolve(engine, CreateJsDisplayObject(engine, display));
97 WLOGFI("JsDisplayManager::OnGetDefaultDisplay success");
98 } else {
99 task.Reject(engine, CreateJsError(engine,
100 static_cast<int32_t>(DMError::DM_ERROR_NULLPTR), "JsDisplayManager::OnGetDefaultDisplay failed."));
101 }
102 };
103 NativeValue* lastParam = nullptr;
104 if (info.argc == ARGC_ONE && info.argv[0]->TypeOf() == NATIVE_FUNCTION) {
105 lastParam = info.argv[0];
106 }
107 NativeValue* result = nullptr;
108 AsyncTask::Schedule(
109 engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
110 return result;
111 }
112
OnGetAllDisplay(NativeEngine & engine,NativeCallbackInfo & info)113 NativeValue* OnGetAllDisplay(NativeEngine& engine, NativeCallbackInfo& info)
114 {
115 WLOGFI("JsDisplayManager::OnGetAllDisplay is called");
116 DMError errCode = DMError::DM_OK;
117 if (info.argc != 0 && info.argc != ARGC_ONE) {
118 WLOGFE("JsDisplayManager::OnGetAllDisplay params not match");
119 errCode = DMError::DM_ERROR_INVALID_PARAM;
120 }
121
122 AsyncTask::CompleteCallback complete =
123 [=](NativeEngine& engine, AsyncTask& task, int32_t status) {
124 if (errCode != DMError::DM_OK) {
125 task.Reject(engine, CreateJsError(engine,
126 static_cast<int32_t>(errCode), "JsDisplayManager::OnGetAllDisplay failed."));
127 }
128 std::vector<sptr<Display>> displays = SingletonContainer::Get<DisplayManager>().GetAllDisplays();
129 if (!displays.empty()) {
130 task.Resolve(engine, CreateJsDisplayArrayObject(engine, displays));
131 WLOGFI("JsDisplayManager::GetAllDisplays success");
132 } else {
133 task.Reject(engine, CreateJsError(engine,
134 static_cast<int32_t>(DMError::DM_ERROR_NULLPTR), "JsDisplayManager::OnGetAllDisplay failed."));
135 }
136 };
137
138 NativeValue* lastParam = nullptr;
139 if (info.argc == ARGC_ONE && info.argv[0]->TypeOf() == NATIVE_FUNCTION) {
140 lastParam = info.argv[0];
141 }
142 NativeValue* result = nullptr;
143 AsyncTask::Schedule(
144 engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
145 return result;
146 }
147
RegisterDisplayListenerWithType(NativeEngine & engine,const std::string & type,NativeValue * value)148 void RegisterDisplayListenerWithType(NativeEngine& engine, const std::string& type, NativeValue* value)
149 {
150 if (IfCallbackRegistered(type, value)) {
151 WLOGFE("JsDisplayManager::RegisterDisplayListenerWithType callback already registered!");
152 return;
153 }
154 std::unique_ptr<NativeReference> callbackRef;
155 callbackRef.reset(engine.CreateReference(value, 1));
156 sptr<JsDisplayListener> displayListener = new(std::nothrow) JsDisplayListener(&engine);
157 if (displayListener == nullptr) {
158 WLOGFE("displayListener is nullptr");
159 return;
160 }
161 if (type == "add" || type == "remove" || type == "change") {
162 SingletonContainer::Get<DisplayManager>().RegisterDisplayListener(displayListener);
163 WLOGFI("JsDisplayManager::RegisterDisplayListenerWithType success");
164 } else {
165 WLOGFE("JsDisplayManager::RegisterDisplayListenerWithType failed method: %{public}s not support!",
166 type.c_str());
167 return;
168 }
169 displayListener->AddCallback(value);
170 jsCbMap_[type][std::move(callbackRef)] = displayListener;
171 }
172
IfCallbackRegistered(const std::string & type,NativeValue * jsListenerObject)173 bool IfCallbackRegistered(const std::string& type, NativeValue* jsListenerObject)
174 {
175 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
176 WLOGFI("JsDisplayManager::IfCallbackRegistered methodName %{public}s not registered!", type.c_str());
177 return false;
178 }
179
180 for (auto& iter : jsCbMap_[type]) {
181 if (jsListenerObject->StrictEquals(iter.first->Get())) {
182 WLOGFE("JsDisplayManager::IfCallbackRegistered callback already registered!");
183 return true;
184 }
185 }
186 return false;
187 }
188
UnregisterAllDisplayListenerWithType(const std::string & type)189 void UnregisterAllDisplayListenerWithType(const std::string& type)
190 {
191 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
192 WLOGFI("JsDisplayManager::UnregisterAllDisplayListenerWithType methodName %{public}s not registered!",
193 type.c_str());
194 return;
195 }
196 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end();) {
197 it->second->RemoveAllCallback();
198 if (type == "add" || type == "remove" || type == "change") {
199 sptr<DisplayManager::IDisplayListener> thisListener(it->second);
200 SingletonContainer::Get<DisplayManager>().UnregisterDisplayListener(thisListener);
201 WLOGFI("JsDisplayManager::UnregisterAllDisplayListenerWithType success");
202 }
203 jsCbMap_[type].erase(it++);
204 }
205 jsCbMap_.erase(type);
206 }
207
UnRegisterDisplayListenerWithType(const std::string & type,NativeValue * value)208 void UnRegisterDisplayListenerWithType(const std::string& type, NativeValue* value)
209 {
210 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
211 WLOGFI("JsDisplayManager::UnRegisterDisplayListenerWithType methodName %{public}s not registered!",
212 type.c_str());
213 return;
214 }
215 for (auto it = jsCbMap_[type].begin(); it != jsCbMap_[type].end();) {
216 if (value->StrictEquals(it->first->Get())) {
217 it->second->RemoveCallback(value);
218 if (type == "add" || type == "remove" || type == "change") {
219 sptr<DisplayManager::IDisplayListener> thisListener(it->second);
220 SingletonContainer::Get<DisplayManager>().UnregisterDisplayListener(thisListener);
221 WLOGFI("JsDisplayManager::UnRegisterDisplayListenerWithType success");
222 }
223 jsCbMap_[type].erase(it++);
224 break;
225 } else {
226 it++;
227 }
228 }
229 if (jsCbMap_[type].empty()) {
230 jsCbMap_.erase(type);
231 }
232 }
233
OnRegisterDisplayManagerCallback(NativeEngine & engine,NativeCallbackInfo & info)234 NativeValue* OnRegisterDisplayManagerCallback(NativeEngine& engine, NativeCallbackInfo& info)
235 {
236 WLOGFI("JsDisplayManager::OnRegisterDisplayManagerCallback is called");
237 if (info.argc != ARGC_TWO) {
238 WLOGFE("JsDisplayManager Params not match: %{public}zu", info.argc);
239 return engine.CreateUndefined();
240 }
241 std::string cbType;
242 if (!ConvertFromJsValue(engine, info.argv[0], cbType)) {
243 WLOGFE("Failed to convert parameter to callbackType");
244 return engine.CreateUndefined();
245 }
246 NativeValue* value = info.argv[INDEX_ONE];
247 if (value == nullptr) {
248 WLOGFI("JsDisplayManager::OnRegisterDisplayManagerCallback info->argv[1] is nullptr");
249 return engine.CreateUndefined();
250 }
251 if (!value->IsCallable()) {
252 WLOGFI("JsDisplayManager::OnRegisterDisplayManagerCallback info->argv[1] is not callable");
253 return engine.CreateUndefined();
254 }
255 std::lock_guard<std::mutex> lock(mtx_);
256 RegisterDisplayListenerWithType(engine, cbType, value);
257 return engine.CreateUndefined();
258 }
259
OnUnregisterDisplayManagerCallback(NativeEngine & engine,NativeCallbackInfo & info)260 NativeValue* OnUnregisterDisplayManagerCallback(NativeEngine& engine, NativeCallbackInfo& info)
261 {
262 WLOGFI("JsDisplayManager::OnUnregisterDisplayCallback is called");
263 if (info.argc == 0) {
264 WLOGFE("JsDisplayManager Params not match %{public}zu", info.argc);
265 return engine.CreateUndefined();
266 }
267 std::string cbType;
268 if (!ConvertFromJsValue(engine, info.argv[0], cbType)) {
269 WLOGFE("Failed to convert parameter to callbackType");
270 return engine.CreateUndefined();
271 }
272 std::lock_guard<std::mutex> lock(mtx_);
273 if (info.argc == ARGC_ONE) {
274 UnregisterAllDisplayListenerWithType(cbType);
275 } else {
276 NativeValue* value = info.argv[INDEX_ONE];
277 if (value == nullptr) {
278 WLOGFI("JsDisplayManager::OnUnregisterDisplayManagerCallback info->argv[1] is nullptr");
279 return engine.CreateUndefined();
280 }
281 if (!value->IsCallable()) {
282 WLOGFI("JsDisplayManager::OnUnregisterDisplayManagerCallback info->argv[1] is not callable");
283 return engine.CreateUndefined();
284 }
285 UnRegisterDisplayListenerWithType(cbType, value);
286 }
287 return engine.CreateUndefined();
288 }
289
CreateJsDisplayArrayObject(NativeEngine & engine,std::vector<sptr<Display>> & displays)290 NativeValue* CreateJsDisplayArrayObject(NativeEngine& engine, std::vector<sptr<Display>>& displays)
291 {
292 WLOGFI("JsDisplayManager::CreateJsDisplayArrayObject is called");
293 NativeValue* arrayValue = engine.CreateArray(displays.size());
294 NativeArray* array = ConvertNativeValueTo<NativeArray>(arrayValue);
295 int32_t i = 0;
296 for (auto& display : displays) {
297 array->SetElement(i++, CreateJsDisplayObject(engine, display));
298 }
299 return arrayValue;
300 }
301 };
302
InitDisplayState(NativeEngine * engine)303 NativeValue* InitDisplayState(NativeEngine* engine)
304 {
305 WLOGFI("JsDisplayManager::InitDisplayState called");
306
307 if (engine == nullptr) {
308 WLOGFE("engine is nullptr");
309 return nullptr;
310 }
311
312 NativeValue *objValue = engine->CreateObject();
313 NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
314 if (object == nullptr) {
315 WLOGFE("Failed to get object");
316 return nullptr;
317 }
318
319 object->SetProperty("STATE_UNKNOWN", CreateJsValue(*engine, static_cast<int32_t>(DisplayStateMode::STATE_UNKNOWN)));
320 object->SetProperty("STATE_OFF", CreateJsValue(*engine, static_cast<int32_t>(DisplayStateMode::STATE_OFF)));
321 object->SetProperty("STATE_ON", CreateJsValue(*engine, static_cast<int32_t>(DisplayStateMode::STATE_ON)));
322 object->SetProperty("STATE_DOZE",
323 CreateJsValue(*engine, static_cast<int32_t>(DisplayStateMode::STATE_DOZE)));
324 object->SetProperty("STATE_DOZE_SUSPEND",
325 CreateJsValue(*engine, static_cast<int32_t>(DisplayStateMode::STATE_DOZE_SUSPEND)));
326 object->SetProperty("STATE_VR",
327 CreateJsValue(*engine, static_cast<int32_t>(DisplayStateMode::STATE_VR)));
328 object->SetProperty("STATE_ON_SUSPEND",
329 CreateJsValue(*engine, static_cast<int32_t>(DisplayStateMode::STATE_ON_SUSPEND)));
330 return objValue;
331 }
332
JsDisplayManagerInit(NativeEngine * engine,NativeValue * exportObj)333 NativeValue* JsDisplayManagerInit(NativeEngine* engine, NativeValue* exportObj)
334 {
335 WLOGFI("JsDisplayManagerInit is called");
336
337 if (engine == nullptr || exportObj == nullptr) {
338 WLOGFE("JsDisplayManagerInit engine or exportObj is nullptr");
339 return nullptr;
340 }
341
342 NativeObject* object = ConvertNativeValueTo<NativeObject>(exportObj);
343 if (object == nullptr) {
344 WLOGFE("JsDisplayManagerInit object is nullptr");
345 return nullptr;
346 }
347
348 object->SetProperty("DisplayState", InitDisplayState(engine));
349
350 std::unique_ptr<JsDisplayManager> jsDisplayManager = std::make_unique<JsDisplayManager>(engine);
351 object->SetNativePointer(jsDisplayManager.release(), JsDisplayManager::Finalizer, nullptr);
352
353 BindNativeFunction(*engine, *object, "getDefaultDisplay", JsDisplayManager::GetDefaultDisplay);
354 BindNativeFunction(*engine, *object, "getAllDisplay", JsDisplayManager::GetAllDisplay);
355 BindNativeFunction(*engine, *object, "on", JsDisplayManager::RegisterDisplayManagerCallback);
356 BindNativeFunction(*engine, *object, "off", JsDisplayManager::UnregisterDisplayManagerCallback);
357 return engine->CreateUndefined();
358 }
359 } // namespace Rosen
360 } // namespace OHOS