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