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