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 "picture_in_picture_controller.h"
17
18 #include <refbase.h>
19 #include <transaction/rs_sync_transaction_controller.h>
20 #include "picture_in_picture_manager.h"
21 #include "window_manager_hilog.h"
22 #include "window_option.h"
23 #include "singleton_container.h"
24
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28 constexpr int32_t PIP_SUCCESS = 1;
29 constexpr int32_t FAILED = 0;
30 constexpr uint32_t PIP_LOW_PRIORITY = 0;
31 constexpr uint32_t PIP_HIGH_PRIORITY = 1;
32 const std::string PIP_CONTENT_PATH = "/system/etc/window/resources/pip_content.abc";
33 const std::string DESTROY_TIMEOUT_TASK = "PipDestroyTimeout";
34 const int DEFAULT_ASPECT_RATIO[] = {16, 9};
35 }
36
GetPipPriority(uint32_t pipTemplateType)37 uint32_t PictureInPictureController::GetPipPriority(uint32_t pipTemplateType)
38 {
39 if (pipTemplateType >= static_cast<uint32_t>(PiPTemplateType::END)) {
40 TLOGE(WmsLogTag::WMS_PIP, "param invalid, pipTemplateType is %{public}d", pipTemplateType);
41 return PIP_LOW_PRIORITY;
42 }
43 if (pipTemplateType == static_cast<uint32_t>(PiPTemplateType::VIDEO_PLAY) ||
44 pipTemplateType == static_cast<uint32_t>(PiPTemplateType::VIDEO_LIVE)) {
45 return PIP_LOW_PRIORITY;
46 } else {
47 return PIP_HIGH_PRIORITY;
48 }
49 }
50
PictureInPictureController(sptr<PipOption> pipOption,sptr<Window> mainWindow,uint32_t windowId,napi_env env)51 PictureInPictureController::PictureInPictureController(sptr<PipOption> pipOption, sptr<Window> mainWindow,
52 uint32_t windowId, napi_env env)
53 : weakRef_(this), pipOption_(pipOption), mainWindow_(mainWindow), mainWindowId_(windowId), env_(env)
54 {
55 curState_ = PiPWindowState::STATE_UNDEFINED;
56 }
57
~PictureInPictureController()58 PictureInPictureController::~PictureInPictureController()
59 {
60 TLOGI(WmsLogTag::WMS_PIP, "Destruction");
61 if (!isAutoStartEnabled_) {
62 return;
63 }
64 PictureInPictureManager::DetachAutoStartController(handleId_, weakRef_);
65 }
66
CreatePictureInPictureWindow(StartPipType startType)67 WMError PictureInPictureController::CreatePictureInPictureWindow(StartPipType startType)
68 {
69 if (pipOption_ == nullptr || pipOption_->GetContext() == nullptr) {
70 TLOGE(WmsLogTag::WMS_PIP, "Create pip failed, invalid pipOption");
71 return WMError::WM_ERROR_PIP_CREATE_FAILED;
72 }
73 mainWindowXComponentController_ = pipOption_->GetXComponentController();
74 if ((mainWindowXComponentController_ == nullptr && !IsTypeNodeEnabled()) || mainWindow_ == nullptr) {
75 TLOGE(WmsLogTag::WMS_PIP, "mainWindowXComponentController or mainWindow is nullptr");
76 return WMError::WM_ERROR_PIP_CREATE_FAILED;
77 }
78 TLOGI(WmsLogTag::WMS_PIP, "mainWindow:%{public}u, mainWindowState:%{public}u",
79 mainWindowId_, mainWindow_->GetWindowState());
80 mainWindowLifeCycleListener_ = sptr<PictureInPictureController::WindowLifeCycleListener>::MakeSptr();
81 mainWindow_->RegisterLifeCycleListener(mainWindowLifeCycleListener_);
82 if (startType != StartPipType::AUTO_START && mainWindow_->GetWindowState() != WindowState::STATE_SHOWN) {
83 TLOGE(WmsLogTag::WMS_PIP, "mainWindow is not shown. create failed.");
84 return WMError::WM_ERROR_PIP_CREATE_FAILED;
85 }
86 UpdateWinRectByComponent();
87 auto windowOption = sptr<WindowOption>::MakeSptr();
88 windowOption->SetWindowName(PIP_WINDOW_NAME);
89 windowOption->SetWindowType(WindowType::WINDOW_TYPE_PIP);
90 windowOption->SetWindowMode(WindowMode::WINDOW_MODE_PIP);
91 windowOption->SetWindowRect(windowRect_);
92 windowOption->SetKeepScreenOn(true);
93 windowOption->SetTouchable(false);
94 WMError errCode = WMError::WM_OK;
95 PiPTemplateInfo pipTemplateInfo;
96 pipTemplateInfo.pipTemplateType = pipOption_->GetPipTemplate();
97 pipTemplateInfo.controlGroup = pipOption_->GetControlGroup();
98 pipTemplateInfo.priority = GetPipPriority(pipOption_->GetPipTemplate());
99 pipTemplateInfo.pipControlStatusInfoList = pipOption_->GetControlStatus();
100 pipTemplateInfo.pipControlEnableInfoList = pipOption_->GetControlEnable();
101 auto context = static_cast<std::weak_ptr<AbilityRuntime::Context>*>(pipOption_->GetContext());
102 const std::shared_ptr<AbilityRuntime::Context>& abilityContext = context->lock();
103 SingletonContainer::Get<PiPReporter>().SetCurrentPackageName(abilityContext->GetApplicationInfo()->name);
104 sptr<Window> window = Window::CreatePiP(windowOption, pipTemplateInfo, context->lock(), errCode);
105 if (window == nullptr || errCode != WMError::WM_OK) {
106 TLOGW(WmsLogTag::WMS_PIP, "Window create failed, reason: %{public}d", errCode);
107 return WMError::WM_ERROR_PIP_CREATE_FAILED;
108 }
109 window_ = window;
110 window_->UpdatePiPRect(windowRect_, WindowSizeChangeReason::PIP_START);
111 PictureInPictureManager::PutPipControllerInfo(window_->GetWindowId(), this);
112 return WMError::WM_OK;
113 }
114
ShowPictureInPictureWindow(StartPipType startType)115 WMError PictureInPictureController::ShowPictureInPictureWindow(StartPipType startType)
116 {
117 TLOGI(WmsLogTag::WMS_PIP, "startType:%{public}u", startType);
118 if (pipOption_ == nullptr) {
119 TLOGE(WmsLogTag::WMS_PIP, "Get PictureInPicture option failed");
120 return WMError::WM_ERROR_PIP_CREATE_FAILED;
121 }
122 if (window_ == nullptr) {
123 TLOGE(WmsLogTag::WMS_PIP, "window is null when show pip");
124 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
125 pipOption_->GetPipTemplate(), FAILED, "window is nullptr");
126 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
127 }
128 for (auto& listener : pipLifeCycleListeners_) {
129 listener->OnPreparePictureInPictureStart();
130 }
131 window_->SetUIContentByAbc(PIP_CONTENT_PATH, env_, nullptr, nullptr);
132 WMError errCode = window_->Show(0, false);
133 if (errCode != WMError::WM_OK) {
134 TLOGE(WmsLogTag::WMS_PIP, "window show failed, err: %{public}u", errCode);
135 for (auto& listener : pipLifeCycleListeners_) {
136 listener->OnPictureInPictureOperationError(static_cast<int32_t>(errCode));
137 }
138 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
139 pipOption_->GetPipTemplate(), FAILED, "window show failed");
140 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
141 }
142 uint32_t requestWidth = 0;
143 uint32_t requestHeight = 0;
144 pipOption_->GetContentSize(requestWidth, requestHeight);
145 WindowSizeChangeReason reason = WindowSizeChangeReason::PIP_SHOW;
146 if (startType == StartPipType::AUTO_START) {
147 reason = WindowSizeChangeReason::PIP_AUTO_START;
148 }
149 if (requestWidth > 0 && requestHeight > 0) {
150 Rect requestRect = {0, 0, requestWidth, requestHeight};
151 window_->UpdatePiPRect(requestRect, reason);
152 } else {
153 window_->UpdatePiPRect(windowRect_, reason);
154 }
155 PictureInPictureManager::SetActiveController(this);
156 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
157 pipOption_->GetPipTemplate(), PIP_SUCCESS, "show pip success");
158 isStoppedFromClient_ = false;
159 return WMError::WM_OK;
160 }
161
StartPictureInPicture(StartPipType startType)162 WMError PictureInPictureController::StartPictureInPicture(StartPipType startType)
163 {
164 TLOGI(WmsLogTag::WMS_PIP, "called");
165 if (pipOption_ == nullptr || pipOption_->GetContext() == nullptr) {
166 TLOGE(WmsLogTag::WMS_PIP, "pipOption is null or Get PictureInPictureOption failed");
167 return WMError::WM_ERROR_PIP_CREATE_FAILED;
168 }
169 if (curState_ == PiPWindowState::STATE_STARTING || curState_ == PiPWindowState::STATE_STARTED) {
170 TLOGW(WmsLogTag::WMS_PIP, "pipWindow is starting, state: %{public}u, id: %{public}u, mainWindow: %{public}u",
171 curState_, (window_ == nullptr) ? INVALID_WINDOW_ID : window_->GetWindowId(), mainWindowId_);
172 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
173 pipOption_->GetPipTemplate(), FAILED, "Pip window is starting");
174 return WMError::WM_ERROR_PIP_REPEAT_OPERATION;
175 }
176 if (!IsPullPiPAndHandleNavigation()) {
177 TLOGE(WmsLogTag::WMS_PIP, "Navigation operate failed");
178 return WMError::WM_ERROR_PIP_CREATE_FAILED;
179 }
180 curState_ = PiPWindowState::STATE_STARTING;
181 if (PictureInPictureManager::HasActiveController() && !PictureInPictureManager::IsActiveController(weakRef_)) {
182 // if current controller is not the active one, but belongs to the same mainWindow, reserve pipWindow
183 if (PictureInPictureManager::IsAttachedToSameWindow(mainWindowId_)) {
184 window_ = PictureInPictureManager::GetCurrentWindow();
185 if (window_ == nullptr) {
186 TLOGE(WmsLogTag::WMS_PIP, "Reuse pipWindow failed");
187 curState_ = PiPWindowState::STATE_UNDEFINED;
188 return WMError::WM_ERROR_PIP_CREATE_FAILED;
189 }
190 TLOGI(WmsLogTag::WMS_PIP, "Reuse pipWindow: %{public}u as attached to the same mainWindow: %{public}u",
191 window_->GetWindowId(), mainWindowId_);
192 PictureInPictureManager::DoClose(false, false);
193 mainWindowXComponentController_ = IsTypeNodeEnabled() ? nullptr : pipOption_->GetXComponentController();
194 UpdateWinRectByComponent();
195 UpdateContentSize(windowRect_.width_, windowRect_.height_);
196 PictureInPictureManager::PutPipControllerInfo(window_->GetWindowId(), this);
197 WMError err = ShowPictureInPictureWindow(startType);
198 if (err != WMError::WM_OK) {
199 curState_ = PiPWindowState::STATE_UNDEFINED;
200 } else {
201 curState_ = PiPWindowState::STATE_STARTED;
202 }
203 return err;
204 }
205 // otherwise, stop the previous one
206 PictureInPictureManager::DoClose(true, true);
207 }
208 return StartPictureInPictureInner(startType);
209 }
210
StartPictureInPictureInner(StartPipType startType)211 WMError PictureInPictureController::StartPictureInPictureInner(StartPipType startType)
212 {
213 WMError errCode = CreatePictureInPictureWindow(startType);
214 if (errCode != WMError::WM_OK) {
215 curState_ = PiPWindowState::STATE_UNDEFINED;
216 TLOGE(WmsLogTag::WMS_PIP, "Create pip window failed, err: %{public}u", errCode);
217 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
218 pipOption_->GetPipTemplate(), FAILED, "Create pip window failed");
219 return errCode;
220 }
221 StartPipType type = startType;
222 if (IsTypeNodeEnabled() && startType != StartPipType::AUTO_START) {
223 type = StartPipType::AUTO_START;
224 }
225 errCode = ShowPictureInPictureWindow(type);
226 if (errCode != WMError::WM_OK) {
227 curState_ = PiPWindowState::STATE_UNDEFINED;
228 TLOGE(WmsLogTag::WMS_PIP, "Show pip window failed, err: %{public}u", errCode);
229 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(type),
230 pipOption_->GetPipTemplate(), FAILED, "Show pip window failed");
231 return errCode;
232 }
233 curState_ = PiPWindowState::STATE_STARTED;
234 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(type),
235 pipOption_->GetPipTemplate(), PIP_SUCCESS, "start pip success");
236 return WMError::WM_OK;
237 }
238
StopPictureInPictureFromClient()239 WMError PictureInPictureController::StopPictureInPictureFromClient()
240 {
241 if (!window_) {
242 TLOGE(WmsLogTag::WMS_PIP, "window is null");
243 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(StopPipType::USER_STOP),
244 pipOption_->GetPipTemplate(), FAILED, "window is null");
245 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
246 }
247 if (curState_ == PiPWindowState::STATE_STOPPING || curState_ == PiPWindowState::STATE_STOPPED ||
248 curState_ == PiPWindowState::STATE_RESTORING) {
249 TLOGE(WmsLogTag::WMS_PIP, "Repeat stop request, curState: %{public}u", curState_);
250 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(StopPipType::USER_STOP),
251 pipOption_->GetPipTemplate(), FAILED, "Repeat stop request");
252 return WMError::WM_ERROR_PIP_REPEAT_OPERATION;
253 }
254 isStoppedFromClient_ = true;
255 WMError res = window_->NotifyPrepareClosePiPWindow();
256 if (res != WMError::WM_OK) {
257 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(StopPipType::USER_STOP),
258 pipOption_->GetPipTemplate(), FAILED, "window destroy failed");
259 return WMError::WM_ERROR_PIP_DESTROY_FAILED;
260 }
261 curState_ = PiPWindowState::STATE_STOPPING;
262 return res;
263 }
264
StopPictureInPicture(bool destroyWindow,StopPipType stopPipType,bool withAnim)265 WMError PictureInPictureController::StopPictureInPicture(bool destroyWindow, StopPipType stopPipType, bool withAnim)
266 {
267 TLOGI(WmsLogTag::WMS_PIP, "destroyWindow: %{public}u anim: %{public}d", destroyWindow, withAnim);
268 if ((!isStoppedFromClient_ && curState_ == PiPWindowState::STATE_STOPPING) ||
269 curState_ == PiPWindowState::STATE_STOPPED) {
270 TLOGE(WmsLogTag::WMS_PIP, "Repeat stop request, curState: %{public}u", curState_);
271 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(stopPipType),
272 pipOption_->GetPipTemplate(), FAILED, "Repeat stop request");
273 return WMError::WM_ERROR_PIP_REPEAT_OPERATION;
274 }
275 if (window_ == nullptr) {
276 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr when stop pip");
277 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(stopPipType),
278 pipOption_->GetPipTemplate(), FAILED, "window_ is nullptr");
279 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
280 }
281 if (curState_ != PiPWindowState::STATE_STOPPING) {
282 curState_ = PiPWindowState::STATE_STOPPING;
283 }
284 for (auto& listener : pipLifeCycleListeners_) {
285 listener->OnPreparePictureInPictureStop();
286 }
287 if (!destroyWindow) {
288 ResetExtController();
289 curState_ = PiPWindowState::STATE_STOPPED;
290 for (auto& listener : pipLifeCycleListeners_) {
291 listener->OnPictureInPictureStop();
292 }
293 PictureInPictureManager::RemoveActiveController(weakRef_);
294 PictureInPictureManager::RemovePipControllerInfo(window_->GetWindowId());
295 return WMError::WM_OK;
296 }
297 return StopPictureInPictureInner(stopPipType, withAnim);
298 }
299
StopPictureInPictureInner(StopPipType stopType,bool withAnim)300 WMError PictureInPictureController::StopPictureInPictureInner(StopPipType stopType, bool withAnim)
301 {
302 uint32_t templateType = 0;
303 if (pipOption_ != nullptr) {
304 templateType = pipOption_->GetPipTemplate();
305 }
306 if (window_ == nullptr) {
307 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr in stop pip inner");
308 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(stopType),
309 templateType, FAILED, "pipController is null");
310 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
311 }
312 auto syncTransactionController = RSSyncTransactionController::GetInstance();
313 if (syncTransactionController) {
314 syncTransactionController->OpenSyncTransaction();
315 }
316 ResetExtController();
317 if (!withAnim) {
318 TLOGI(WmsLogTag::WMS_PIP, "DestroyPictureInPictureWindow without animation");
319 DestroyPictureInPictureWindow();
320 }
321 if (syncTransactionController) {
322 syncTransactionController->CloseSyncTransaction();
323 }
324
325 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(stopType),
326 templateType, PIP_SUCCESS, "pip window stop success");
327 return WMError::WM_OK;
328 }
329
DestroyPictureInPictureWindow()330 WMError PictureInPictureController::DestroyPictureInPictureWindow()
331 {
332 TLOGI(WmsLogTag::WMS_PIP, "called");
333 if (window_ == nullptr) {
334 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr when destroy pip");
335 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
336 }
337 WmErrorCode ret = WM_JS_TO_ERROR_CODE_MAP.at(window_->Destroy());
338 if (ret != WmErrorCode::WM_OK) {
339 curState_ = PiPWindowState::STATE_UNDEFINED;
340 TLOGE(WmsLogTag::WMS_PIP, "window destroy failed, err:%{public}u", ret);
341 for (auto& listener : pipLifeCycleListeners_) {
342 listener->OnPictureInPictureOperationError(static_cast<int32_t>(ret));
343 }
344 return WMError::WM_ERROR_PIP_DESTROY_FAILED;
345 }
346
347 for (auto& listener : pipLifeCycleListeners_) {
348 listener->OnPictureInPictureStop();
349 }
350 curState_ = PiPWindowState::STATE_STOPPED;
351 std::string navId = pipOption_ == nullptr ? "" : pipOption_->GetNavigationId();
352 if (!navId.empty() && mainWindow_ && !IsTypeNodeEnabled()) {
353 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
354 if (navController) {
355 navController->DeletePIPMode(handleId_);
356 TLOGI(WmsLogTag::WMS_PIP, "Delete pip mode id: %{public}d", handleId_);
357 }
358 }
359 if (mainWindow_ != nullptr) {
360 mainWindow_->UnregisterLifeCycleListener(mainWindowLifeCycleListener_);
361 }
362 mainWindowLifeCycleListener_ = nullptr;
363 PictureInPictureManager::RemovePipControllerInfo(window_->GetWindowId());
364 window_ = nullptr;
365 PictureInPictureManager::RemoveActiveController(this);
366 return WMError::WM_OK;
367 }
368
GetPipWindow() const369 sptr<Window> PictureInPictureController::GetPipWindow() const
370 {
371 return window_;
372 }
373
GetMainWindowId()374 uint32_t PictureInPictureController::GetMainWindowId()
375 {
376 return mainWindowId_;
377 }
378
SetPipWindow(sptr<Window> window)379 void PictureInPictureController::SetPipWindow(sptr<Window> window)
380 {
381 window_ = window;
382 }
383
SetAutoStartEnabled(bool enable)384 void PictureInPictureController::SetAutoStartEnabled(bool enable)
385 {
386 TLOGI(WmsLogTag::WMS_PIP, "enable: %{public}u, mainWindow: %{public}u", enable, mainWindowId_);
387 isAutoStartEnabled_ = enable;
388 if (mainWindow_ == nullptr) {
389 return;
390 }
391 if (!pipOption_) {
392 TLOGE(WmsLogTag::WMS_PIP, "pipOption is null");
393 return;
394 }
395 uint32_t priority = GetPipPriority(pipOption_->GetPipTemplate());
396 mainWindow_->SetAutoStartPiP(enable, priority);
397 if (isAutoStartEnabled_) {
398 // cache navigation here as we cannot get containerId while BG
399 if (!IsPullPiPAndHandleNavigation()) {
400 TLOGE(WmsLogTag::WMS_PIP, "Navigation operate failed");
401 return;
402 }
403 PictureInPictureManager::AttachAutoStartController(handleId_, weakRef_);
404 } else {
405 PictureInPictureManager::DetachAutoStartController(handleId_, weakRef_);
406 if (IsTypeNodeEnabled()) {
407 TLOGI(WmsLogTag::WMS_PIP, "typeNode enabled");
408 return;
409 }
410 std::string navId = pipOption_->GetNavigationId();
411 if (!navId.empty()) {
412 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
413 if (navController) {
414 navController->DeletePIPMode(handleId_);
415 TLOGI(WmsLogTag::WMS_PIP, "Delete pip mode id: %{public}d", handleId_);
416 }
417 }
418 }
419 }
420
IsAutoStartEnabled(bool & enable) const421 void PictureInPictureController::IsAutoStartEnabled(bool& enable) const
422 {
423 enable = isAutoStartEnabled_;
424 }
425
GetControllerState()426 PiPWindowState PictureInPictureController::GetControllerState()
427 {
428 return curState_;
429 }
430
UpdateContentSize(int32_t width,int32_t height)431 void PictureInPictureController::UpdateContentSize(int32_t width, int32_t height)
432 {
433 if (width <= 0 || height <= 0) {
434 TLOGE(WmsLogTag::WMS_PIP, "invalid size");
435 return;
436 }
437 pipOption_->SetContentSize(static_cast<uint32_t>(width), static_cast<uint32_t>(height));
438 if (curState_ != PiPWindowState::STATE_STARTED) {
439 TLOGD(WmsLogTag::WMS_PIP, "UpdateContentSize is disabled when state: %{public}u", curState_);
440 return;
441 }
442 if (window_ == nullptr) {
443 TLOGE(WmsLogTag::WMS_PIP, "pipWindow not exist");
444 return;
445 }
446 if (mainWindowXComponentController_ && !IsTypeNodeEnabled()) {
447 float posX = 0;
448 float posY = 0;
449 float newWidth = 0;
450 float newHeight = 0;
451 mainWindowXComponentController_->GetGlobalPosition(posX, posY);
452 mainWindowXComponentController_->GetSize(newWidth, newHeight);
453 bool isSizeChange = IsContentSizeChanged(newWidth, newHeight, posX, posY);
454 if (isSizeChange) {
455 Rect r = {static_cast<int32_t>(posX), static_cast<int32_t>(posY),
456 static_cast<uint32_t>(newWidth), static_cast<uint32_t>(newHeight)};
457 window_->UpdatePiPRect(r, WindowSizeChangeReason::TRANSFORM);
458 }
459 }
460 TLOGI(WmsLogTag::WMS_PIP, "UpdateContentSize window: %{public}u width:%{public}u height:%{public}u",
461 window_->GetWindowId(), width, height);
462 Rect rect = {0, 0, width, height};
463 window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RATIO_CHANGE);
464 SingletonContainer::Get<PiPReporter>().ReportPiPRatio(width, height);
465 }
466
467
UpdatePiPControlStatus(PiPControlType controlType,PiPControlStatus status)468 void PictureInPictureController::UpdatePiPControlStatus(PiPControlType controlType, PiPControlStatus status)
469 {
470 TLOGI(WmsLogTag::WMS_PIP, "controlType:%{public}u, status:%{public}d", controlType, status);
471 if (static_cast<int32_t>(status) < -1) {
472 pipOption_->SetPiPControlEnabled(controlType, status);
473 } else {
474 pipOption_->SetPiPControlStatus(controlType, status);
475 }
476 if (window_ == nullptr) {
477 TLOGE(WmsLogTag::WMS_PIP, "pipWindow not exist");
478 return;
479 }
480 window_->UpdatePiPControlStatus(controlType, status);
481 }
482
IsContentSizeChanged(float width,float height,float posX,float posY)483 bool PictureInPictureController::IsContentSizeChanged(float width, float height, float posX, float posY)
484 {
485 return windowRect_.width_ != static_cast<uint32_t>(width) ||
486 windowRect_.height_ != static_cast<uint32_t>(height) ||
487 windowRect_.posX_ != static_cast<int32_t>(posX) || windowRect_.posY_ != static_cast<int32_t>(posY);
488 }
489
AfterDestroyed()490 void PictureInPictureController::WindowLifeCycleListener::AfterDestroyed()
491 {
492 TLOGI(WmsLogTag::WMS_PIP, "stop picture_in_picture when attached window destroy");
493 PictureInPictureManager::DoClose(true, true);
494 }
495
DoActionEvent(const std::string & actionName,int32_t status)496 void PictureInPictureController::DoActionEvent(const std::string& actionName, int32_t status)
497 {
498 TLOGI(WmsLogTag::WMS_PIP, "actionName: %{public}s", actionName.c_str());
499 SingletonContainer::Get<PiPReporter>().ReportPiPActionEvent(pipOption_->GetPipTemplate(), actionName);
500 for (auto& listener : pipActionObservers_) {
501 listener->OnActionEvent(actionName, status);
502 }
503 if (CONTROL_TYPE_MAP.find(actionName) != CONTROL_TYPE_MAP.end()) {
504 pipOption_->SetPiPControlStatus(CONTROL_TYPE_MAP[actionName], static_cast<PiPControlStatus>(status));
505 }
506 }
507
PreRestorePictureInPicture()508 void PictureInPictureController::PreRestorePictureInPicture()
509 {
510 TLOGI(WmsLogTag::WMS_PIP, "called");
511 curState_ = PiPWindowState::STATE_RESTORING;
512 for (auto& listener : pipLifeCycleListeners_) {
513 listener->OnRestoreUserInterface();
514 }
515 }
516
DoControlEvent(PiPControlType controlType,PiPControlStatus status)517 void PictureInPictureController::DoControlEvent(PiPControlType controlType, PiPControlStatus status)
518 {
519 TLOGI(WmsLogTag::WMS_PIP, "controlType:%{public}u, enabled:%{public}d", controlType, status);
520 if (pipOption_ == nullptr) {
521 TLOGE(WmsLogTag::WMS_PIP, "pipOption_ is nullptr");
522 return;
523 }
524 SingletonContainer::Get<PiPReporter>().ReportPiPControlEvent(pipOption_->GetPipTemplate(), controlType);
525 for (auto& listener : pipControlObservers_) {
526 listener->OnControlEvent(controlType, status);
527 }
528 pipOption_->SetPiPControlStatus(controlType, status);
529 }
530
PipSizeChange(uint32_t width,uint32_t height,double scale)531 void PictureInPictureController::PipSizeChange(uint32_t width, uint32_t height, double scale)
532 {
533 TLOGI(WmsLogTag::WMS_PIP, "notify size info width: %{public}u, height: %{public}u scale: %{public}f",
534 width, height, scale);
535 PiPWindowSize windowSize;
536 windowSize.width = width;
537 windowSize.height = height;
538 windowSize.scale = scale;
539 for (auto& listener : pipWindowSizeListeners_) {
540 listener->OnPipSizeChange(windowSize);
541 }
542 }
543
RestorePictureInPictureWindow()544 void PictureInPictureController::RestorePictureInPictureWindow()
545 {
546 StopPictureInPicture(true, StopPipType::NULL_STOP, true);
547 SingletonContainer::Get<PiPReporter>().ReportPiPRestore();
548 TLOGI(WmsLogTag::WMS_PIP, "restore pip main window finished");
549 }
550
PrepareSource()551 void PictureInPictureController::PrepareSource()
552 {
553 TLOGI(WmsLogTag::WMS_PIP, "in");
554 if (IsTypeNodeEnabled()) {
555 TLOGI(WmsLogTag::WMS_PIP, "typeNode enabled");
556 return;
557 }
558 if (mainWindow_ == nullptr) {
559 TLOGE(WmsLogTag::WMS_PIP, "mainWindow is nullptr");
560 return;
561 }
562 std::string navId = pipOption_->GetNavigationId();
563 if (navId != "") {
564 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
565 if (navController) {
566 navController->PushInPIP(handleId_);
567 TLOGI(WmsLogTag::WMS_PIP, "Push in pip handleId: %{public}d", handleId_);
568 } else {
569 TLOGE(WmsLogTag::WMS_PIP, "navController is nullptr");
570 }
571 }
572 }
573
LocateSource()574 void PictureInPictureController::LocateSource()
575 {
576 TLOGI(WmsLogTag::WMS_PIP, "in");
577 if (window_ == nullptr) {
578 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr");
579 return;
580 }
581 window_->SetTransparent(true);
582 UpdatePiPSourceRect();
583 }
584
UpdateWinRectByComponent()585 void PictureInPictureController::UpdateWinRectByComponent()
586 {
587 if (IsTypeNodeEnabled()) {
588 uint32_t contentWidth = 0;
589 uint32_t contentHeight = 0;
590 pipOption_->GetContentSize(contentWidth, contentHeight);
591 if (contentWidth == 0 || contentHeight == 0) {
592 contentWidth = DEFAULT_ASPECT_RATIO[0];
593 contentHeight = DEFAULT_ASPECT_RATIO[1];
594 }
595 windowRect_.posX_ = 0;
596 windowRect_.posY_ = 0;
597 windowRect_.width_ = contentWidth;
598 windowRect_.height_ = contentHeight;
599 return;
600 }
601 if (!mainWindowXComponentController_) {
602 TLOGE(WmsLogTag::WMS_PIP, "main window xComponent not set");
603 return;
604 }
605 float posX = 0;
606 float posY = 0;
607 float width = 0;
608 float height = 0;
609 mainWindowXComponentController_->GetGlobalPosition(posX, posY);
610 mainWindowXComponentController_->GetSize(width, height);
611 windowRect_.width_ = static_cast<uint32_t>(width);
612 windowRect_.height_ = static_cast<uint32_t>(height);
613 if (windowRect_.width_ == 0 || windowRect_.height_ == 0) {
614 uint32_t contentWidth = 0;
615 uint32_t contentHeight = 0;
616 pipOption_->GetContentSize(contentWidth, contentHeight);
617 windowRect_.width_ = contentWidth;
618 windowRect_.height_ = contentHeight;
619 }
620 windowRect_.posX_ = static_cast<int32_t>(posX);
621 windowRect_.posY_ = static_cast<int32_t>(posY);
622 TLOGD(WmsLogTag::WMS_PIP, "position width: %{public}u, height: %{public}u, posX: %{public}d, posY: %{public}d",
623 windowRect_.width_, windowRect_.height_, windowRect_.posX_, windowRect_.posY_);
624 }
625
UpdatePiPSourceRect() const626 void PictureInPictureController::UpdatePiPSourceRect() const
627 {
628 if (IsTypeNodeEnabled() && window_ != nullptr) {
629 Rect rect = {0, 0, 0, 0};
630 TLOGI(WmsLogTag::WMS_PIP, "use typeNode, unable to locate source rect");
631 window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RESTORE);
632 return;
633 }
634 if (mainWindowXComponentController_ == nullptr || window_ == nullptr) {
635 TLOGE(WmsLogTag::WMS_PIP, "xcomponent controller not valid");
636 return;
637 }
638 float posX = 0;
639 float posY = 0;
640 float width = 0;
641 float height = 0;
642 mainWindowXComponentController_->GetGlobalPosition(posX, posY);
643 mainWindowXComponentController_->GetSize(width, height);
644 Rect rect = { posX, posY, width, height };
645 TLOGI(WmsLogTag::WMS_PIP, "result rect: [%{public}d, %{public}d, %{public}u, %{public}u]",
646 rect.posX_, rect.posY_, rect.width_, rect.height_);
647 window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RESTORE);
648 }
649
ResetExtController()650 void PictureInPictureController::ResetExtController()
651 {
652 TLOGI(WmsLogTag::WMS_PIP, "called");
653 if (IsTypeNodeEnabled()) {
654 TLOGI(WmsLogTag::WMS_PIP, "skip resetExtController as nodeController enabled");
655 return;
656 }
657 if (mainWindowXComponentController_ == nullptr || pipXComponentController_ == nullptr) {
658 TLOGE(WmsLogTag::WMS_PIP, "error when resetExtController, one of the xComponentController is null");
659 return;
660 }
661 XComponentControllerErrorCode errorCode =
662 mainWindowXComponentController_->ResetExtController(pipXComponentController_);
663 if (errorCode != XComponentControllerErrorCode::XCOMPONENT_CONTROLLER_NO_ERROR) {
664 TLOGE(WmsLogTag::WMS_PIP, "swap xComponent failed, errorCode: %{public}u", errorCode);
665 }
666 }
667
SetXComponentController(std::shared_ptr<XComponentController> xComponentController)668 WMError PictureInPictureController::SetXComponentController(std::shared_ptr<XComponentController> xComponentController)
669 {
670 TLOGI(WmsLogTag::WMS_PIP, "called");
671 if (IsTypeNodeEnabled()) {
672 TLOGI(WmsLogTag::WMS_PIP, "skip as nodeController enabled");
673 return WMError::WM_OK;
674 }
675 pipXComponentController_ = xComponentController;
676 if (window_ == nullptr) {
677 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr when set XComponentController");
678 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
679 }
680 if (mainWindowXComponentController_ == nullptr || pipXComponentController_ == nullptr) {
681 TLOGE(WmsLogTag::WMS_PIP, "error when setXController, one of the xComponentController is null");
682 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
683 }
684 XComponentControllerErrorCode errorCode =
685 mainWindowXComponentController_->SetExtController(pipXComponentController_);
686 if (errorCode != XComponentControllerErrorCode::XCOMPONENT_CONTROLLER_NO_ERROR) {
687 TLOGE(WmsLogTag::WMS_PIP, "swap xComponent failed, errorCode: %{public}u", errorCode);
688 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
689 }
690 OnPictureInPictureStart();
691 return WMError::WM_OK;
692 }
693
OnPictureInPictureStart()694 void PictureInPictureController::OnPictureInPictureStart()
695 {
696 for (auto& listener : pipLifeCycleListeners_) {
697 listener->OnPictureInPictureStart();
698 }
699 }
700
IsTypeNodeEnabled() const701 bool PictureInPictureController::IsTypeNodeEnabled() const
702 {
703 return pipOption_ != nullptr ? pipOption_->IsTypeNodeEnabled() : false;
704 }
705
RegisterPiPLifecycle(const sptr<IPiPLifeCycle> & listener)706 WMError PictureInPictureController::RegisterPiPLifecycle(const sptr<IPiPLifeCycle>& listener)
707 {
708 return RegisterListener(pipLifeCycleListeners_, listener);
709 }
710
RegisterPiPActionObserver(const sptr<IPiPActionObserver> & listener)711 WMError PictureInPictureController::RegisterPiPActionObserver(const sptr<IPiPActionObserver>& listener)
712 {
713 return RegisterListener(pipActionObservers_, listener);
714 }
715
RegisterPiPControlObserver(const sptr<IPiPControlObserver> & listener)716 WMError PictureInPictureController::RegisterPiPControlObserver(const sptr<IPiPControlObserver>& listener)
717 {
718 return RegisterListener(pipControlObservers_, listener);
719 }
720
RegisterPiPWindowSize(const sptr<IPiPWindowSize> & listener)721 WMError PictureInPictureController::RegisterPiPWindowSize(const sptr<IPiPWindowSize>& listener)
722 {
723 return RegisterListener(pipWindowSizeListeners_, listener);
724 }
725
UnregisterPiPLifecycle(const sptr<IPiPLifeCycle> & listener)726 WMError PictureInPictureController::UnregisterPiPLifecycle(const sptr<IPiPLifeCycle>& listener)
727 {
728 return UnregisterListener(pipLifeCycleListeners_, listener);
729 }
730
UnregisterPiPActionObserver(const sptr<IPiPActionObserver> & listener)731 WMError PictureInPictureController::UnregisterPiPActionObserver(const sptr<IPiPActionObserver>& listener)
732 {
733 return UnregisterListener(pipActionObservers_, listener);
734 }
735
UnregisterPiPControlObserver(const sptr<IPiPControlObserver> & listener)736 WMError PictureInPictureController::UnregisterPiPControlObserver(const sptr<IPiPControlObserver>& listener)
737 {
738 return UnregisterListener(pipControlObservers_, listener);
739 }
740
UnregisterPiPWindowSize(const sptr<IPiPWindowSize> & listener)741 WMError PictureInPictureController::UnregisterPiPWindowSize(const sptr<IPiPWindowSize>& listener)
742 {
743 return UnregisterListener(pipWindowSizeListeners_, listener);
744 }
745
746 template<typename T>
RegisterListener(std::vector<sptr<T>> & holder,const sptr<T> & listener)747 WMError PictureInPictureController::RegisterListener(std::vector<sptr<T>>& holder, const sptr<T>& listener)
748 {
749 if (listener == nullptr) {
750 TLOGE(WmsLogTag::WMS_PIP, "listener is nullptr");
751 return WMError::WM_ERROR_NULLPTR;
752 }
753 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
754 TLOGE(WmsLogTag::WMS_PIP, "Listener already registered");
755 return WMError::WM_OK;
756 }
757 holder.emplace_back(listener);
758 return WMError::WM_OK;
759 }
760
761 template<typename T>
UnregisterListener(std::vector<sptr<T>> & holder,const sptr<T> & listener)762 WMError PictureInPictureController::UnregisterListener(std::vector<sptr<T>>& holder, const sptr<T>& listener)
763 {
764 if (listener == nullptr) {
765 TLOGE(WmsLogTag::WMS_PIP, "listener could not be null");
766 return WMError::WM_ERROR_NULLPTR;
767 }
768 holder.erase(std::remove_if(holder.begin(), holder.end(),
769 [listener](const sptr<T>& registeredListener) {
770 return registeredListener == listener;
771 }), holder.end());
772 return WMError::WM_OK;
773 }
774
IsPullPiPAndHandleNavigation()775 bool PictureInPictureController::IsPullPiPAndHandleNavigation()
776 {
777 if (IsTypeNodeEnabled()) {
778 TLOGI(WmsLogTag::WMS_PIP, "App use typeNode");
779 return true;
780 }
781 if (pipOption_->GetNavigationId() == "") {
782 TLOGI(WmsLogTag::WMS_PIP, "App not use navigation");
783 return true;
784 }
785 if (mainWindow_ == nullptr) {
786 TLOGE(WmsLogTag::WMS_PIP, "Main window init error");
787 return false;
788 }
789 std::string navId = pipOption_->GetNavigationId();
790 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
791 if (navController) {
792 if (navController->IsNavDestinationInTopStack()) {
793 handleId_ = navController->GetTopHandle();
794 if (handleId_ == -1) {
795 TLOGE(WmsLogTag::WMS_PIP, "Get top handle error");
796 return false;
797 }
798 if (firstHandleId_ != -1) {
799 handleId_ = firstHandleId_;
800 navController->SetInPIPMode(handleId_);
801 TLOGI(WmsLogTag::WMS_PIP, "Cache first navigation");
802 } else {
803 TLOGI(WmsLogTag::WMS_PIP, "First top handle id: %{public}d", handleId_);
804 firstHandleId_ = handleId_;
805 navController->SetInPIPMode(handleId_);
806 }
807 return true;
808 } else {
809 TLOGE(WmsLogTag::WMS_PIP, "Top is not navDestination");
810 return false;
811 }
812 } else {
813 TLOGE(WmsLogTag::WMS_PIP, "Get navController error");
814 }
815 return false;
816 }
817
GetPiPNavigationId()818 std::string PictureInPictureController::GetPiPNavigationId()
819 {
820 return (pipOption_ != nullptr && !IsTypeNodeEnabled()) ? pipOption_->GetNavigationId() : "";
821 }
822
GetCustomNodeController()823 napi_ref PictureInPictureController::GetCustomNodeController()
824 {
825 return pipOption_ == nullptr ? nullptr : pipOption_->GetNodeControllerRef();
826 }
827
GetTypeNode() const828 napi_ref PictureInPictureController::GetTypeNode() const
829 {
830 return pipOption_ == nullptr ? nullptr : pipOption_->GetTypeNodeRef();
831 }
832 } // namespace Rosen
833 } // namespace OHOS