• 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, "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