• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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