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
RestorePictureInPictureWindow()531 void PictureInPictureController::RestorePictureInPictureWindow()
532 {
533 StopPictureInPicture(true, StopPipType::NULL_STOP, true);
534 SingletonContainer::Get<PiPReporter>().ReportPiPRestore();
535 TLOGI(WmsLogTag::WMS_PIP, "restore pip main window finished");
536 }
537
PrepareSource()538 void PictureInPictureController::PrepareSource()
539 {
540 TLOGI(WmsLogTag::WMS_PIP, "in");
541 if (IsTypeNodeEnabled()) {
542 TLOGI(WmsLogTag::WMS_PIP, "typeNode enabled");
543 return;
544 }
545 if (mainWindow_ == nullptr) {
546 TLOGE(WmsLogTag::WMS_PIP, "mainWindow is nullptr");
547 return;
548 }
549 std::string navId = pipOption_->GetNavigationId();
550 if (navId != "") {
551 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
552 if (navController) {
553 navController->PushInPIP(handleId_);
554 TLOGI(WmsLogTag::WMS_PIP, "Push in pip handleId: %{public}d", handleId_);
555 } else {
556 TLOGE(WmsLogTag::WMS_PIP, "navController is nullptr");
557 }
558 }
559 }
560
LocateSource()561 void PictureInPictureController::LocateSource()
562 {
563 TLOGI(WmsLogTag::WMS_PIP, "in");
564 if (window_ == nullptr) {
565 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr");
566 return;
567 }
568 window_->SetTransparent(true);
569 UpdatePiPSourceRect();
570 }
571
UpdateWinRectByComponent()572 void PictureInPictureController::UpdateWinRectByComponent()
573 {
574 if (IsTypeNodeEnabled()) {
575 uint32_t contentWidth = 0;
576 uint32_t contentHeight = 0;
577 pipOption_->GetContentSize(contentWidth, contentHeight);
578 if (contentWidth == 0 || contentHeight == 0) {
579 contentWidth = DEFAULT_ASPECT_RATIO[0];
580 contentHeight = DEFAULT_ASPECT_RATIO[1];
581 }
582 windowRect_.posX_ = 0;
583 windowRect_.posY_ = 0;
584 windowRect_.width_ = contentWidth;
585 windowRect_.height_ = contentHeight;
586 return;
587 }
588 if (!mainWindowXComponentController_) {
589 TLOGE(WmsLogTag::WMS_PIP, "main window xComponent not set");
590 return;
591 }
592 float posX = 0;
593 float posY = 0;
594 float width = 0;
595 float height = 0;
596 mainWindowXComponentController_->GetGlobalPosition(posX, posY);
597 mainWindowXComponentController_->GetSize(width, height);
598 windowRect_.width_ = static_cast<uint32_t>(width);
599 windowRect_.height_ = static_cast<uint32_t>(height);
600 if (windowRect_.width_ == 0 || windowRect_.height_ == 0) {
601 uint32_t contentWidth = 0;
602 uint32_t contentHeight = 0;
603 pipOption_->GetContentSize(contentWidth, contentHeight);
604 windowRect_.width_ = contentWidth;
605 windowRect_.height_ = contentHeight;
606 }
607 windowRect_.posX_ = static_cast<int32_t>(posX);
608 windowRect_.posY_ = static_cast<int32_t>(posY);
609 TLOGD(WmsLogTag::WMS_PIP, "position width: %{public}u, height: %{public}u, posX: %{public}d, posY: %{public}d",
610 windowRect_.width_, windowRect_.height_, windowRect_.posX_, windowRect_.posY_);
611 }
612
UpdatePiPSourceRect() const613 void PictureInPictureController::UpdatePiPSourceRect() const
614 {
615 if (IsTypeNodeEnabled() && window_ != nullptr) {
616 Rect rect = {0, 0, 0, 0};
617 TLOGI(WmsLogTag::WMS_PIP, "use typeNode, unable to locate source rect");
618 window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RESTORE);
619 return;
620 }
621 if (mainWindowXComponentController_ == nullptr || window_ == nullptr) {
622 TLOGE(WmsLogTag::WMS_PIP, "xcomponent controller not valid");
623 return;
624 }
625 float posX = 0;
626 float posY = 0;
627 float width = 0;
628 float height = 0;
629 mainWindowXComponentController_->GetGlobalPosition(posX, posY);
630 mainWindowXComponentController_->GetSize(width, height);
631 Rect rect = { posX, posY, width, height };
632 TLOGI(WmsLogTag::WMS_PIP, "result rect: [%{public}d, %{public}d, %{public}u, %{public}u]",
633 rect.posX_, rect.posY_, rect.width_, rect.height_);
634 window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RESTORE);
635 }
636
ResetExtController()637 void PictureInPictureController::ResetExtController()
638 {
639 TLOGI(WmsLogTag::WMS_PIP, "called");
640 if (IsTypeNodeEnabled()) {
641 TLOGI(WmsLogTag::WMS_PIP, "skip resetExtController as nodeController enabled");
642 return;
643 }
644 if (mainWindowXComponentController_ == nullptr || pipXComponentController_ == nullptr) {
645 TLOGE(WmsLogTag::WMS_PIP, "error when resetExtController, one of the xComponentController is null");
646 return;
647 }
648 XComponentControllerErrorCode errorCode =
649 mainWindowXComponentController_->ResetExtController(pipXComponentController_);
650 if (errorCode != XComponentControllerErrorCode::XCOMPONENT_CONTROLLER_NO_ERROR) {
651 TLOGE(WmsLogTag::WMS_PIP, "swap xComponent failed, errorCode: %{public}u", errorCode);
652 }
653 }
654
SetXComponentController(std::shared_ptr<XComponentController> xComponentController)655 WMError PictureInPictureController::SetXComponentController(std::shared_ptr<XComponentController> xComponentController)
656 {
657 TLOGI(WmsLogTag::WMS_PIP, "called");
658 if (IsTypeNodeEnabled()) {
659 TLOGI(WmsLogTag::WMS_PIP, "skip as nodeController enabled");
660 return WMError::WM_OK;
661 }
662 pipXComponentController_ = xComponentController;
663 if (window_ == nullptr) {
664 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr when set XComponentController");
665 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
666 }
667 if (mainWindowXComponentController_ == nullptr || pipXComponentController_ == nullptr) {
668 TLOGE(WmsLogTag::WMS_PIP, "error when setXController, one of the xComponentController is null");
669 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
670 }
671 XComponentControllerErrorCode errorCode =
672 mainWindowXComponentController_->SetExtController(pipXComponentController_);
673 if (errorCode != XComponentControllerErrorCode::XCOMPONENT_CONTROLLER_NO_ERROR) {
674 TLOGE(WmsLogTag::WMS_PIP, "swap xComponent failed, errorCode: %{public}u", errorCode);
675 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
676 }
677 OnPictureInPictureStart();
678 return WMError::WM_OK;
679 }
680
OnPictureInPictureStart()681 void PictureInPictureController::OnPictureInPictureStart()
682 {
683 for (auto& listener : pipLifeCycleListeners_) {
684 listener->OnPictureInPictureStart();
685 }
686 }
687
IsTypeNodeEnabled() const688 bool PictureInPictureController::IsTypeNodeEnabled() const
689 {
690 return pipOption_ != nullptr ? pipOption_->IsTypeNodeEnabled() : false;
691 }
692
RegisterPiPLifecycle(const sptr<IPiPLifeCycle> & listener)693 WMError PictureInPictureController::RegisterPiPLifecycle(const sptr<IPiPLifeCycle>& listener)
694 {
695 return RegisterListener(pipLifeCycleListeners_, listener);
696 }
697
RegisterPiPActionObserver(const sptr<IPiPActionObserver> & listener)698 WMError PictureInPictureController::RegisterPiPActionObserver(const sptr<IPiPActionObserver>& listener)
699 {
700 return RegisterListener(pipActionObservers_, listener);
701 }
702
RegisterPiPControlObserver(const sptr<IPiPControlObserver> & listener)703 WMError PictureInPictureController::RegisterPiPControlObserver(const sptr<IPiPControlObserver>& listener)
704 {
705 return RegisterListener(pipControlObservers_, listener);
706 }
707
UnregisterPiPLifecycle(const sptr<IPiPLifeCycle> & listener)708 WMError PictureInPictureController::UnregisterPiPLifecycle(const sptr<IPiPLifeCycle>& listener)
709 {
710 return UnregisterListener(pipLifeCycleListeners_, listener);
711 }
712
UnregisterPiPActionObserver(const sptr<IPiPActionObserver> & listener)713 WMError PictureInPictureController::UnregisterPiPActionObserver(const sptr<IPiPActionObserver>& listener)
714 {
715 return UnregisterListener(pipActionObservers_, listener);
716 }
717
UnregisterPiPControlObserver(const sptr<IPiPControlObserver> & listener)718 WMError PictureInPictureController::UnregisterPiPControlObserver(const sptr<IPiPControlObserver>& listener)
719 {
720 return UnregisterListener(pipControlObservers_, listener);
721 }
722
723 template<typename T>
RegisterListener(std::vector<sptr<T>> & holder,const sptr<T> & listener)724 WMError PictureInPictureController::RegisterListener(std::vector<sptr<T>>& holder, const sptr<T>& listener)
725 {
726 if (listener == nullptr) {
727 TLOGE(WmsLogTag::WMS_PIP, "listener is nullptr");
728 return WMError::WM_ERROR_NULLPTR;
729 }
730 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
731 TLOGE(WmsLogTag::WMS_PIP, "Listener already registered");
732 return WMError::WM_OK;
733 }
734 holder.emplace_back(listener);
735 return WMError::WM_OK;
736 }
737
738 template<typename T>
UnregisterListener(std::vector<sptr<T>> & holder,const sptr<T> & listener)739 WMError PictureInPictureController::UnregisterListener(std::vector<sptr<T>>& holder, const sptr<T>& listener)
740 {
741 if (listener == nullptr) {
742 TLOGE(WmsLogTag::WMS_PIP, "listener could not be null");
743 return WMError::WM_ERROR_NULLPTR;
744 }
745 holder.erase(std::remove_if(holder.begin(), holder.end(),
746 [listener](const sptr<T>& registeredListener) {
747 return registeredListener == listener;
748 }), holder.end());
749 return WMError::WM_OK;
750 }
751
IsPullPiPAndHandleNavigation()752 bool PictureInPictureController::IsPullPiPAndHandleNavigation()
753 {
754 if (IsTypeNodeEnabled()) {
755 TLOGI(WmsLogTag::WMS_PIP, "App use typeNode");
756 return true;
757 }
758 if (pipOption_->GetNavigationId() == "") {
759 TLOGI(WmsLogTag::WMS_PIP, "App not use navigation");
760 return true;
761 }
762 if (mainWindow_ == nullptr) {
763 TLOGE(WmsLogTag::WMS_PIP, "Main window init error");
764 return false;
765 }
766 std::string navId = pipOption_->GetNavigationId();
767 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
768 if (navController) {
769 if (navController->IsNavDestinationInTopStack()) {
770 handleId_ = navController->GetTopHandle();
771 if (handleId_ != -1) {
772 TLOGD(WmsLogTag::WMS_PIP, "Top handle id : %{public}d", handleId_);
773 navController->SetInPIPMode(handleId_);
774 return true;
775 } else {
776 TLOGE(WmsLogTag::WMS_PIP, "Get top handle error");
777 return false;
778 }
779 } else {
780 TLOGE(WmsLogTag::WMS_PIP, "Top is not navDestination");
781 return false;
782 }
783 } else {
784 TLOGE(WmsLogTag::WMS_PIP, "Get navController error");
785 }
786 return false;
787 }
788
GetPiPNavigationId()789 std::string PictureInPictureController::GetPiPNavigationId()
790 {
791 return (pipOption_ != nullptr && !IsTypeNodeEnabled()) ? pipOption_->GetNavigationId() : "";
792 }
793
GetCustomNodeController()794 napi_ref PictureInPictureController::GetCustomNodeController()
795 {
796 return pipOption_ == nullptr ? nullptr : pipOption_->GetNodeControllerRef();
797 }
798
GetTypeNode() const799 napi_ref PictureInPictureController::GetTypeNode() const
800 {
801 return pipOption_ == nullptr ? nullptr : pipOption_->GetTypeNodeRef();
802 }
803 } // namespace Rosen
804 } // namespace OHOS