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