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