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