1 /*
2 * Copyright (c) 2023-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_pip_controller.h"
17 #include "js_pip_utils.h"
18 #include "picture_in_picture_manager.h"
19 #include "window_manager_hilog.h"
20
21 namespace OHOS {
22 namespace Rosen {
23 using namespace AbilityRuntime;
24 namespace {
25 constexpr int32_t NUMBER_ZERO = 0;
26 constexpr int32_t NUMBER_ONE = 1;
27 constexpr int32_t NUMBER_TWO = 2;
28 constexpr int32_t NUMBER_FOUR = 4;
29 const std::string STATE_CHANGE_CB = "stateChange";
30 const std::string CONTROL_PANEL_ACTION_EVENT_CB = "controlPanelActionEvent";
31 const std::string CONTROL_EVENT_CB = "controlEvent";
32 const std::string SIZE_CHANGE_CB = "pipWindowSizeChange";
33 }
34
BindFunctions(napi_env env,napi_value object,const char * moduleName)35 void BindFunctions(napi_env env, napi_value object, const char* moduleName)
36 {
37 BindNativeFunction(env, object, "startPiP", moduleName, JsPipController::StartPictureInPicture);
38 BindNativeFunction(env, object, "stopPiP", moduleName, JsPipController::StopPictureInPicture);
39 BindNativeFunction(env, object, "updateContentNode", moduleName, JsPipController::UpdateContentNode);
40 BindNativeFunction(env, object, "updateContentSize", moduleName, JsPipController::UpdateContentSize);
41 BindNativeFunction(env, object, "updatePiPControlStatus", moduleName, JsPipController::UpdatePiPControlStatus);
42 BindNativeFunction(env, object, "setAutoStartEnabled", moduleName, JsPipController::SetAutoStartEnabled);
43 BindNativeFunction(env, object, "setPiPControlEnabled", moduleName, JsPipController::SetPiPControlEnabled);
44 BindNativeFunction(env, object, "getPiPWindowInfo", moduleName, JsPipController::GetPiPWindowInfo);
45 BindNativeFunction(env, object, "on", moduleName, JsPipController::RegisterCallback);
46 BindNativeFunction(env, object, "off", moduleName, JsPipController::UnregisterCallback);
47 // test api
48 BindNativeFunction(env, object, "isPiPSupported", moduleName, JsPipController::PictureInPicturePossible);
49 }
50
CreateJsPipControllerObject(napi_env env,sptr<PictureInPictureController> & pipController)51 napi_value CreateJsPipControllerObject(napi_env env, sptr<PictureInPictureController>& pipController)
52 {
53 napi_value objValue = nullptr;
54 napi_status status = napi_create_object(env, &objValue);
55 if (status != napi_ok || objValue == nullptr) {
56 TLOGE(WmsLogTag::WMS_PIP, "failed to create js obj, error:%{public}d", status);
57 return NapiGetUndefined(env);
58 }
59
60 TLOGI(WmsLogTag::WMS_PIP, "CreateJsPipController");
61 std::unique_ptr<JsPipController> jsPipController = std::make_unique<JsPipController>(pipController);
62 napi_wrap(env, objValue, jsPipController.release(), JsPipController::Finalizer, nullptr, nullptr);
63
64 BindFunctions(env, objValue, "JsPipController");
65 return objValue;
66 }
67
JsPipController(const sptr<PictureInPictureController> & pipController)68 JsPipController::JsPipController(const sptr<PictureInPictureController>& pipController)
69 : pipController_(pipController)
70 {
71 listenerCodeMap_ = {
72 { STATE_CHANGE_CB, ListenerType::STATE_CHANGE_CB },
73 { CONTROL_PANEL_ACTION_EVENT_CB, ListenerType::CONTROL_PANEL_ACTION_EVENT_CB },
74 { CONTROL_EVENT_CB, ListenerType::CONTROL_EVENT_CB },
75 { SIZE_CHANGE_CB, ListenerType::SIZE_CHANGE_CB },
76 };
77 }
78
~JsPipController()79 JsPipController::~JsPipController()
80 {
81 }
82
Finalizer(napi_env env,void * data,void * hint)83 void JsPipController::Finalizer(napi_env env, void* data, void* hint)
84 {
85 TLOGD(WmsLogTag::WMS_PIP, "Finalizer is called");
86 std::unique_ptr<JsPipController>(static_cast<JsPipController*>(data));
87 }
88
StartPictureInPicture(napi_env env,napi_callback_info info)89 napi_value JsPipController::StartPictureInPicture(napi_env env, napi_callback_info info)
90 {
91 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
92 return (me != nullptr) ? me->OnStartPictureInPicture(env, info) : nullptr;
93 }
94
OnStartPictureInPicture(napi_env env,napi_callback_info info)95 napi_value JsPipController::OnStartPictureInPicture(napi_env env, napi_callback_info info)
96 {
97 TLOGI(WmsLogTag::WMS_PIP, "OnStartPictureInPicture is called");
98 if (PictureInPictureManager::ShouldAbortPipStart()) {
99 TLOGI(WmsLogTag::WMS_PIP, "OnStartPictureInPicture abort");
100 return NapiGetUndefined(env);
101 }
102
103 napi_value result = nullptr;
104 std::shared_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, nullptr, &result);
105 auto asyncTask = [this, env, task = napiAsyncTask,
106 weak = wptr<PictureInPictureController>(pipController_)]() {
107 auto pipController = weak.promote();
108 if (pipController == nullptr) {
109 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_PIP_STATE_ABNORMALLY),
110 "JsPipController::OnStartPictureInPicture failed."));
111 return;
112 }
113 WMError errCode = pipController->StartPictureInPicture(StartPipType::USER_START);
114 if (errCode != WMError::WM_OK) {
115 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WM_JS_TO_ERROR_CODE_MAP.at(errCode)),
116 "JsPipController::OnStartPictureInPicture failed."));
117 return;
118 }
119 task->Resolve(env, NapiGetUndefined(env));
120 };
121 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
122 napiAsyncTask->Reject(env, CreateJsError(env,
123 static_cast<int32_t>(WMError::WM_ERROR_PIP_INTERNAL_ERROR), "Send event failed"));
124 }
125 return result;
126 }
127
StopPictureInPicture(napi_env env,napi_callback_info info)128 napi_value JsPipController::StopPictureInPicture(napi_env env, napi_callback_info info)
129 {
130 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
131 return (me != nullptr) ? me->OnStopPictureInPicture(env, info) : nullptr;
132 }
133
OnStopPictureInPicture(napi_env env,napi_callback_info info)134 napi_value JsPipController::OnStopPictureInPicture(napi_env env, napi_callback_info info)
135 {
136 TLOGI(WmsLogTag::WMS_PIP, "OnStopPictureInPicture is called");
137 napi_value result = nullptr;
138 std::shared_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, nullptr, &result);
139 auto asyncTask = [this, env, task = napiAsyncTask,
140 weak = wptr<PictureInPictureController>(pipController_)]() {
141 auto pipController = weak.promote();
142 if (pipController == nullptr) {
143 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY),
144 "JsPipController::OnStopPictureInPicture failed."));
145 return;
146 }
147 WMError errCode = pipController->StopPictureInPictureFromClient();
148 if (errCode != WMError::WM_OK) {
149 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WM_JS_TO_ERROR_CODE_MAP.at(errCode)),
150 "JsPipController::OnStopPictureInPicture failed."));
151 return;
152 }
153 task->Resolve(env, NapiGetUndefined(env));
154 };
155 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
156 napiAsyncTask->Reject(env, CreateJsError(env,
157 static_cast<int32_t>(WMError::WM_ERROR_PIP_INTERNAL_ERROR), "Send event failed"));
158 }
159 return result;
160 }
161
SetAutoStartEnabled(napi_env env,napi_callback_info info)162 napi_value JsPipController::SetAutoStartEnabled(napi_env env, napi_callback_info info)
163 {
164 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
165 return (me != nullptr) ? me->OnSetAutoStartEnabled(env, info) : nullptr;
166 }
167
OnSetAutoStartEnabled(napi_env env,napi_callback_info info)168 napi_value JsPipController::OnSetAutoStartEnabled(napi_env env, napi_callback_info info)
169 {
170 TLOGI(WmsLogTag::WMS_PIP, "OnSetAutoStartEnabled is called");
171 size_t argc = NUMBER_FOUR;
172 napi_value argv[NUMBER_FOUR] = {nullptr};
173 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
174 if (argc != 1) {
175 TLOGE(WmsLogTag::WMS_PIP, "Argc count is invalid: %{public}zu", argc);
176 return NapiThrowInvalidParam(env);
177 }
178 bool enable = false;
179 if (!ConvertFromJsValue(env, argv[0], enable)) {
180 TLOGE(WmsLogTag::WMS_PIP, "Failed to convert parameter to bool");
181 return NapiGetUndefined(env);
182 }
183 if (pipController_ == nullptr) {
184 TLOGE(WmsLogTag::WMS_PIP, "error, controller is nullptr");
185 return NapiGetUndefined(env);
186 }
187 pipController_->SetAutoStartEnabled(enable);
188 return NapiGetUndefined(env);
189 }
190
UpdateContentNode(napi_env env,napi_callback_info info)191 napi_value JsPipController::UpdateContentNode(napi_env env, napi_callback_info info)
192 {
193 JsPipController *me = CheckParamsAndGetThis<JsPipController>(env, info);
194 return (me != nullptr) ? me->OnUpdateContentNode(env, info) : nullptr;
195 }
196
OnUpdateContentNode(napi_env env,napi_callback_info info)197 napi_value JsPipController::OnUpdateContentNode(napi_env env, napi_callback_info info)
198 {
199 TLOGI(WmsLogTag::WMS_PIP, "OnUpdateContentNode is called");
200 size_t argc = NUMBER_FOUR;
201 napi_value argv[NUMBER_FOUR] = {nullptr};
202 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
203 if (argc != NUMBER_ONE) {
204 TLOGE(WmsLogTag::WMS_PIP, "Argc count is invalid:%{public}zu", argc);
205 return NapiThrowInvalidParam(env, "Invalid args count, 1 arg is needed.");
206 }
207 napi_value typeNode = argv[0];
208 if (GetType(env, typeNode) == napi_null || GetType(env, typeNode) == napi_undefined) {
209 TLOGE(WmsLogTag::WMS_PIP, "Invalid typeNode");
210 return NapiThrowInvalidParam(env, "Invalid typeNode.");
211 }
212 napi_ref typeNodeRef = nullptr;
213 napi_create_reference(env, typeNode, NUMBER_ONE, &typeNodeRef);
214 napi_value result = nullptr;
215 std::shared_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, nullptr, &result);
216 auto asyncTask = [env, task = napiAsyncTask, typeNodeRef,
217 weak = wptr<PictureInPictureController>(pipController_)]() {
218 if (!PictureInPictureManager::IsSupportPiP()) {
219 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_DEVICE_NOT_SUPPORT),
220 "Capability not supported. Failed to call the API due to limited device capabilities."));
221 napi_delete_reference(env, typeNodeRef);
222 return;
223 }
224 auto pipController = weak.promote();
225 if (pipController == nullptr) {
226 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_PIP_INTERNAL_ERROR),
227 "PiP internal error."));
228 napi_delete_reference(env, typeNodeRef);
229 return;
230 }
231 napi_ref oldTypeNodeRef = pipController->GetTypeNode();
232 pipController->UpdateContentNodeRef(typeNodeRef);
233 if (oldTypeNodeRef != nullptr) {
234 napi_delete_reference(env, oldTypeNodeRef);
235 oldTypeNodeRef = nullptr;
236 }
237 task->Resolve(env, NapiGetUndefined(env));
238 };
239 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
240 napi_delete_reference(env, typeNodeRef);
241 napiAsyncTask->Reject(env, CreateJsError(env,
242 static_cast<int32_t>(WMError::WM_ERROR_PIP_INTERNAL_ERROR), "Send event failed"));
243 }
244 return result;
245 }
246
UpdateContentSize(napi_env env,napi_callback_info info)247 napi_value JsPipController::UpdateContentSize(napi_env env, napi_callback_info info)
248 {
249 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
250 return (me != nullptr) ? me->OnUpdateContentSize(env, info) : nullptr;
251 }
252
OnUpdateContentSize(napi_env env,napi_callback_info info)253 napi_value JsPipController::OnUpdateContentSize(napi_env env, napi_callback_info info)
254 {
255 TLOGI(WmsLogTag::WMS_PIP, "OnUpdateContentSize is called");
256 size_t argc = NUMBER_FOUR;
257 napi_value argv[NUMBER_FOUR] = {nullptr};
258 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
259 if (argc != NUMBER_TWO) {
260 TLOGE(WmsLogTag::WMS_PIP, "Invalid args count, need 2 args but received: %{public}zu", argc);
261 return NapiThrowInvalidParam(env, "Invalid args count, 2 args is needed.");
262 }
263 int32_t width = 0;
264 std::string errMsg = "";
265 if (!ConvertFromJsValue(env, argv[0], width) || width <= 0) {
266 errMsg = "Failed to convert parameter to int or width <= 0";
267 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
268 return NapiThrowInvalidParam(env, errMsg);
269 }
270 int32_t height = 0;
271 if (!ConvertFromJsValue(env, argv[1], height) || height <= 0) {
272 errMsg = "Failed to convert parameter to int or height <= 0";
273 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
274 return NapiThrowInvalidParam(env, errMsg);
275 }
276 if (pipController_ == nullptr) {
277 errMsg = "OnUpdateContentSize error, controller is nullptr";
278 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
279 return NapiThrowInvalidParam(env, errMsg);
280 }
281 pipController_->UpdateContentSize(width, height);
282 return NapiGetUndefined(env);
283 }
284
UpdatePiPControlStatus(napi_env env,napi_callback_info info)285 napi_value JsPipController::UpdatePiPControlStatus(napi_env env, napi_callback_info info)
286 {
287 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
288 return (me != nullptr) ? me->OnUpdatePiPControlStatus(env, info) : nullptr;
289 }
290
OnUpdatePiPControlStatus(napi_env env,napi_callback_info info)291 napi_value JsPipController::OnUpdatePiPControlStatus(napi_env env, napi_callback_info info)
292 {
293 TLOGI(WmsLogTag::WMS_PIP, "called");
294 size_t argc = NUMBER_FOUR;
295 napi_value argv[NUMBER_FOUR] = {nullptr};
296 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
297 if (argc != NUMBER_TWO) {
298 TLOGE(WmsLogTag::WMS_PIP, "Invalid args count, need 2 args but received: %{public}zu", argc);
299 return NapiThrowInvalidParam(env, "Invalid args count, 2 args is needed.");
300 }
301 auto controlType = PiPControlType::VIDEO_PLAY_PAUSE;
302 std::string errMsg;
303 if (!ConvertFromJsValue(env, argv[0], controlType)) {
304 errMsg = "Failed to convert parameter to int or controlType < 0";
305 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
306 return NapiThrowInvalidParam(env, errMsg);
307 }
308 auto status = PiPControlStatus::PLAY;
309 if (!ConvertFromJsValue(env, argv[1], status)) {
310 errMsg = "Failed to convert parameter to int";
311 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
312 return NapiThrowInvalidParam(env, errMsg);
313 }
314 if (pipController_ == nullptr) {
315 errMsg = "OnUpdatePiPControlStatus error, controller is nullptr";
316 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
317 return NapiThrowInvalidParam(env, errMsg);
318 }
319 pipController_->UpdatePiPControlStatus(controlType, status);
320 return NapiGetUndefined(env);
321 }
322
SetPiPControlEnabled(napi_env env,napi_callback_info info)323 napi_value JsPipController::SetPiPControlEnabled(napi_env env, napi_callback_info info)
324 {
325 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
326 return (me != nullptr) ? me->OnSetPiPControlEnabled(env, info) : nullptr;
327 }
328
OnSetPiPControlEnabled(napi_env env,napi_callback_info info)329 napi_value JsPipController::OnSetPiPControlEnabled(napi_env env, napi_callback_info info)
330 {
331 TLOGI(WmsLogTag::WMS_PIP, "called");
332 size_t argc = NUMBER_FOUR;
333 napi_value argv[NUMBER_FOUR] = {nullptr};
334 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
335 if (argc != NUMBER_TWO) {
336 TLOGE(WmsLogTag::WMS_PIP, "Invalid args count, need 2 args but received: %{public}zu", argc);
337 return NapiThrowInvalidParam(env, "Invalid args count, 2 args is needed.");
338 }
339 auto controlType = PiPControlType::VIDEO_PLAY_PAUSE;
340 std::string errMsg = "";
341 if (!ConvertFromJsValue(env, argv[0], controlType)) {
342 errMsg = "Failed to convert parameter to int";
343 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
344 return NapiThrowInvalidParam(env, errMsg);
345 }
346 bool enabled = true;
347 if (!ConvertFromJsValue(env, argv[1], enabled)) {
348 errMsg = "Failed to convert parameter to bool";
349 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
350 return NapiThrowInvalidParam(env, errMsg);
351 }
352 if (pipController_ == nullptr) {
353 errMsg = "OnSetPiPControlEnabled error, controller is nullptr";
354 TLOGE(WmsLogTag::WMS_PIP, "%{public}s", errMsg.c_str());
355 return NapiThrowInvalidParam(env, errMsg);
356 }
357 pipController_->UpdatePiPControlStatus(controlType, enabled ?
358 PiPControlStatus::ENABLED : PiPControlStatus::DISABLED);
359 return NapiGetUndefined(env);
360 }
361
GetPiPWindowInfo(napi_env env,napi_callback_info info)362 napi_value JsPipController::GetPiPWindowInfo(napi_env env, napi_callback_info info)
363 {
364 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
365 return (me != nullptr) ? me->OnGetPiPWindowInfo(env, info) : nullptr;
366 }
367
OnGetPiPWindowInfo(napi_env env,napi_callback_info info)368 napi_value JsPipController::OnGetPiPWindowInfo(napi_env env, napi_callback_info info)
369 {
370 TLOGI(WmsLogTag::WMS_PIP, "called");
371 napi_value result = nullptr;
372 std::shared_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, nullptr, &result);
373 auto asyncTask = [this, env, task = napiAsyncTask,
374 weak = wptr<PictureInPictureController>(pipController_)]() {
375 if (!PictureInPictureManager::IsSupportPiP()) {
376 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_DEVICE_NOT_SUPPORT),
377 "Capability not supported. Failed to call the API due to limited device capabilities."));
378 return;
379 }
380 auto pipController = weak.promote();
381 if (pipController == nullptr) {
382 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_PIP_INTERNAL_ERROR),
383 "PiP internal error."));
384 return;
385 }
386 const sptr<Window>& pipWindow = pipController->GetPipWindow();
387 if (pipWindow == nullptr) {
388 TLOGE(WmsLogTag::WMS_PIP, "Failed to get pip window");
389 task->Reject(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_PIP_INTERNAL_ERROR),
390 "PiP internal error."));
391 return;
392 }
393 task->Resolve(env, CreateJsPiPWindowInfoObject(env, pipWindow));
394 };
395 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
396 napiAsyncTask->Reject(env, CreateJsError(env,
397 static_cast<int32_t>(WMError::WM_ERROR_PIP_INTERNAL_ERROR), "Send event failed"));
398 }
399 return result;
400 }
401
RegisterCallback(napi_env env,napi_callback_info info)402 napi_value JsPipController::RegisterCallback(napi_env env, napi_callback_info info)
403 {
404 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
405 return (me != nullptr) ? me->OnRegisterCallback(env, info) : nullptr;
406 }
407
OnRegisterCallback(napi_env env,napi_callback_info info)408 napi_value JsPipController::OnRegisterCallback(napi_env env, napi_callback_info info)
409 {
410 TLOGI(WmsLogTag::WMS_PIP, "OnRegisterCallback is called");
411 size_t argc = NUMBER_FOUR;
412 napi_value argv[NUMBER_FOUR] = {nullptr};
413 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
414 if (argc < NUMBER_TWO) {
415 TLOGE(WmsLogTag::WMS_PIP, "JsPipController Params not match: %{public}zu", argc);
416 return NapiThrowInvalidParam(env);
417 }
418 std::string cbType = "";
419 if (!ConvertFromJsValue(env, argv[0], cbType)) {
420 TLOGE(WmsLogTag::WMS_PIP, "Failed to convert parameter to callbackType");
421 return NapiThrowInvalidParam(env);
422 }
423 napi_value value = argv[1];
424 if (value == nullptr || !NapiIsCallable(env, value)) {
425 TLOGE(WmsLogTag::WMS_PIP, "Callback is nullptr or not callable");
426 return NapiThrowInvalidParam(env);
427 }
428 WmErrorCode ret = RegisterListenerWithType(env, cbType, value);
429 if (ret != WmErrorCode::WM_OK) {
430 TLOGE(WmsLogTag::WMS_PIP, "OnRegisterCallback failed");
431 return NapiThrowInvalidParam(env);
432 }
433 return NapiGetUndefined(env);
434 }
435
RegisterListenerWithType(napi_env env,const std::string & type,napi_value value)436 WmErrorCode JsPipController::RegisterListenerWithType(napi_env env, const std::string& type, napi_value value)
437 {
438 if (IfCallbackRegistered(env, type, value)) {
439 TLOGE(WmsLogTag::WMS_PIP, "Callback already registered!");
440 return WmErrorCode::WM_ERROR_INVALID_CALLING;
441 }
442 std::shared_ptr<NativeReference> callbackRef;
443 napi_ref result = nullptr;
444 napi_create_reference(env, value, 1, &result);
445 callbackRef.reset(reinterpret_cast<NativeReference*>(result));
446 auto pipWindowListener = sptr<JsPiPWindowListener>::MakeSptr(env, callbackRef);
447 if (pipWindowListener == nullptr) {
448 TLOGE(WmsLogTag::WMS_PIP, "New JsPiPWindowListener failed");
449 return WmErrorCode::WM_ERROR_STATE_ABNORMALLY;
450 }
451 jsCbMap_[type].insert(pipWindowListener);
452
453 switch (listenerCodeMap_[type]) {
454 case ListenerType::STATE_CHANGE_CB:
455 ProcessStateChangeRegister(pipWindowListener);
456 break;
457 case ListenerType::CONTROL_PANEL_ACTION_EVENT_CB:
458 ProcessActionEventRegister(pipWindowListener);
459 break;
460 case ListenerType::CONTROL_EVENT_CB:
461 ProcessControlEventRegister(pipWindowListener);
462 break;
463 case ListenerType::SIZE_CHANGE_CB:
464 ProcessSizeChangeRegister(pipWindowListener);
465 break;
466 default:
467 break;
468 }
469 TLOGI(WmsLogTag::WMS_PIP, "Register type %{public}s success! callback map size: %{public}zu",
470 type.c_str(), jsCbMap_[type].size());
471 return WmErrorCode::WM_OK;
472 }
473
IfCallbackRegistered(napi_env env,const std::string & type,napi_value jsListenerObject)474 bool JsPipController::IfCallbackRegistered(napi_env env, const std::string& type, napi_value jsListenerObject)
475 {
476 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
477 TLOGI(WmsLogTag::WMS_PIP, "methodName %{public}s not registered!", type.c_str());
478 return false;
479 }
480 for (auto& listener : jsCbMap_[type]) {
481 bool isEquals = false;
482 napi_strict_equals(env, jsListenerObject, listener->GetCallbackRef()->GetNapiValue(), &isEquals);
483 if (isEquals) {
484 TLOGE(WmsLogTag::WMS_PIP, "Callback already registered!");
485 return true;
486 }
487 }
488 return false;
489 }
490
ProcessStateChangeRegister(const sptr<JsPiPWindowListener> & listener)491 void JsPipController::ProcessStateChangeRegister(const sptr<JsPiPWindowListener>& listener)
492 {
493 if (pipController_ == nullptr) {
494 TLOGE(WmsLogTag::WMS_PIP, "controller is nullptr");
495 return;
496 }
497 sptr<IPiPLifeCycle> thisListener(listener);
498 pipController_->RegisterPiPLifecycle(thisListener);
499 }
500
ProcessActionEventRegister(const sptr<JsPiPWindowListener> & listener)501 void JsPipController::ProcessActionEventRegister(const sptr<JsPiPWindowListener>& listener)
502 {
503 if (pipController_ == nullptr) {
504 TLOGE(WmsLogTag::WMS_PIP, "controller is nullptr");
505 return;
506 }
507 sptr<IPiPActionObserver> thisListener(listener);
508 pipController_->RegisterPiPActionObserver(listener);
509 }
510
ProcessControlEventRegister(const sptr<JsPiPWindowListener> & listener)511 void JsPipController::ProcessControlEventRegister(const sptr<JsPiPWindowListener>& listener)
512 {
513 if (pipController_ == nullptr) {
514 TLOGE(WmsLogTag::WMS_PIP, "controller is nullptr");
515 return;
516 }
517 sptr<IPiPControlObserver> thisListener(listener);
518 pipController_->RegisterPiPControlObserver(thisListener);
519 }
520
ProcessSizeChangeRegister(const sptr<JsPiPWindowListener> & listener)521 void JsPipController::ProcessSizeChangeRegister(const sptr<JsPiPWindowListener>& listener)
522 {
523 if (pipController_ == nullptr) {
524 TLOGE(WmsLogTag::WMS_PIP, "controller is nullptr");
525 return;
526 }
527 sptr<IPiPWindowSize> thisListener(listener);
528 pipController_->RegisterPiPWindowSize(thisListener);
529 }
530
ProcessStateChangeUnRegister(const sptr<JsPiPWindowListener> & listener)531 void JsPipController::ProcessStateChangeUnRegister(const sptr<JsPiPWindowListener>& listener)
532 {
533 if (pipController_ == nullptr) {
534 TLOGE(WmsLogTag::WMS_PIP, "controller is nullptr");
535 return;
536 }
537 sptr<IPiPLifeCycle> thisListener(listener);
538 pipController_->UnregisterPiPLifecycle(thisListener);
539 }
540
ProcessActionEventUnRegister(const sptr<JsPiPWindowListener> & listener)541 void JsPipController::ProcessActionEventUnRegister(const sptr<JsPiPWindowListener>& listener)
542 {
543 if (pipController_ == nullptr) {
544 TLOGE(WmsLogTag::WMS_PIP, "controller is nullptr");
545 return;
546 }
547 sptr<IPiPActionObserver> thisListener(listener);
548 pipController_->UnregisterPiPActionObserver(thisListener);
549 }
550
ProcessControlEventUnRegister(const sptr<JsPiPWindowListener> & listener)551 void JsPipController::ProcessControlEventUnRegister(const sptr<JsPiPWindowListener>& listener)
552 {
553 if (pipController_ == nullptr) {
554 TLOGE(WmsLogTag::WMS_PIP, "controller is nullptr");
555 return;
556 }
557 sptr<IPiPControlObserver> thisListener(listener);
558 pipController_->UnregisterPiPControlObserver(thisListener);
559 }
560
ProcessSizeChangeUnRegister(const sptr<JsPiPWindowListener> & listener)561 void JsPipController::ProcessSizeChangeUnRegister(const sptr<JsPiPWindowListener>& listener)
562 {
563 if (pipController_ == nullptr) {
564 TLOGE(WmsLogTag::WMS_PIP, "controller is nullptr");
565 return;
566 }
567 sptr<IPiPWindowSize> thisListener(listener);
568 pipController_->UnregisterPiPWindowSize(thisListener);
569 }
570
UnregisterCallback(napi_env env,napi_callback_info info)571 napi_value JsPipController::UnregisterCallback(napi_env env, napi_callback_info info)
572 {
573 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
574 return (me != nullptr) ? me->OnUnregisterCallback(env, info) : nullptr;
575 }
576
OnUnregisterCallback(napi_env env,napi_callback_info info)577 napi_value JsPipController::OnUnregisterCallback(napi_env env, napi_callback_info info)
578 {
579 size_t argc = NUMBER_FOUR;
580 napi_value argv[NUMBER_FOUR] = {nullptr};
581 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
582 if (argc == NUMBER_ZERO || argc > NUMBER_TWO) {
583 TLOGE(WmsLogTag::WMS_PIP, "JsPipController Params not match: %{public}zu", argc);
584 return NapiThrowInvalidParam(env);
585 }
586 std::string cbType = "";
587 if (!ConvertFromJsValue(env, argv[0], cbType)) {
588 TLOGE(WmsLogTag::WMS_PIP, "Failed to convert parameter to string");
589 return NapiThrowInvalidParam(env);
590 }
591 if (argc == NUMBER_ONE) {
592 UnRegisterListenerWithType(env, cbType, nullptr);
593 return NapiGetUndefined(env);
594 }
595 napi_value value = argv[NUMBER_ONE];
596 if (value != nullptr && NapiIsCallable(env, value)) {
597 UnRegisterListenerWithType(env, cbType, value);
598 }
599 return NapiGetUndefined(env);
600 }
601
UnRegisterListenerWithType(napi_env env,const std::string & type,napi_value value)602 WmErrorCode JsPipController::UnRegisterListenerWithType(napi_env env, const std::string& type, napi_value value)
603 {
604 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
605 TLOGI(WmsLogTag::WMS_PIP, "methodName %{public}s not registered!", type.c_str());
606 return WmErrorCode::WM_ERROR_INVALID_CALLING;
607 }
608
609 if (value == nullptr) {
610 for (auto& listener : jsCbMap_[type]) {
611 WmErrorCode ret = UnRegisterListener(type, listener);
612 if (ret != WmErrorCode::WM_OK) {
613 TLOGE(WmsLogTag::WMS_PIP, "Unregister type %{public}s failed, no value", type.c_str());
614 return ret;
615 }
616 }
617 jsCbMap_.erase(type);
618 } else {
619 bool foundCallbackValue = false;
620 for (auto& listener : jsCbMap_[type]) {
621 bool isEquals = false;
622 napi_strict_equals(env, value, listener->GetCallbackRef()->GetNapiValue(), &isEquals);
623 if (!isEquals) {
624 continue;
625 }
626 foundCallbackValue = true;
627 WmErrorCode ret = UnRegisterListener(type, listener);
628 if (ret != WmErrorCode::WM_OK) {
629 TLOGE(WmsLogTag::WMS_PIP, "Unregister type %{public}s failed", type.c_str());
630 return ret;
631 }
632 jsCbMap_[type].erase(listener);
633 break;
634 }
635 if (!foundCallbackValue) {
636 TLOGE(WmsLogTag::WMS_PIP, "Unregister type %{public}s failed because not found callback!", type.c_str());
637 return WmErrorCode::WM_OK;
638 }
639 if (jsCbMap_[type].empty()) {
640 jsCbMap_.erase(type);
641 }
642 }
643 TLOGI(WmsLogTag::WMS_PIP, "Unregister type %{public}s success!", type.c_str());
644 return WmErrorCode::WM_OK;
645 }
646
UnRegisterListener(const std::string & type,const sptr<JsPiPWindowListener> & pipWindowListener)647 WmErrorCode JsPipController::UnRegisterListener(const std::string& type,
648 const sptr<JsPiPWindowListener>& pipWindowListener)
649 {
650 switch (listenerCodeMap_[type]) {
651 case ListenerType::STATE_CHANGE_CB:
652 ProcessStateChangeUnRegister(pipWindowListener);
653 break;
654 case ListenerType::CONTROL_PANEL_ACTION_EVENT_CB:
655 ProcessActionEventUnRegister(pipWindowListener);
656 break;
657 case ListenerType::CONTROL_EVENT_CB:
658 ProcessControlEventUnRegister(pipWindowListener);
659 break;
660 case ListenerType::SIZE_CHANGE_CB:
661 ProcessSizeChangeUnRegister(pipWindowListener);
662 break;
663 default:
664 break;
665 }
666 return WmErrorCode::WM_OK;
667 }
668
PictureInPicturePossible(napi_env env,napi_callback_info info)669 napi_value JsPipController::PictureInPicturePossible(napi_env env, napi_callback_info info)
670 {
671 JsPipController* me = CheckParamsAndGetThis<JsPipController>(env, info);
672 return (me != nullptr) ? me->OnPictureInPicturePossible(env, info) : nullptr;
673 }
674
OnPictureInPicturePossible(napi_env env,napi_callback_info info)675 napi_value JsPipController::OnPictureInPicturePossible(napi_env env, napi_callback_info info)
676 {
677 TLOGI(WmsLogTag::WMS_PIP, "called");
678 bool isPiPSupported = false;
679 if (pipController_ == nullptr) {
680 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_PIP_INTERNAL_ERROR),
681 "PiP internal error."));
682 TLOGE(WmsLogTag::WMS_PIP, "error, controller is nullptr");
683 return CreateJsValue(env, isPiPSupported);
684 }
685 pipController_->GetPipPossible(isPiPSupported);
686 return CreateJsValue(env, isPiPSupported);
687 }
688 } // namespace Rosen
689 } // namespace OHOS
690