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