* Copyright (c) 2023-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "picture_in_picture_controller.h"
#include "picture_in_picture_manager.h"
#include "float_window_manager.h"
#include "singleton_container.h"
#include "window_manager_hilog.h"
#include <ui/rs_ui_context.h>
namespace OHOS {
namespace Rosen {
namespace {
const std::string PIP_CONTENT_PATH = "/system/etc/window/resources/pip_content.abc";
const std::string DESTROY_TIMEOUT_TASK = "PipDestroyTimeout";
const std::string STATE_CHANGE_WM = "stateChange";
const std::string UPDATE_NODE = "nodeUpdate";
const int32_t INVALID_HANDLE_ID = -1;
}
PictureInPictureController::PictureInPictureController(sptr<PipOption> pipOption, sptr<Window> mainWindow,
uint32_t windowId, napi_env env)
: PictureInPictureControllerBase(pipOption, mainWindow, windowId, env)
{
weakRef_ = this;
}
PictureInPictureController::~PictureInPictureController()
{
TLOGI(WmsLogTag::WMS_PIP, "Destruction");
if (!isAutoStartEnabled_) {
return;
}
PictureInPictureManager::DetachAutoStartController(handleId_, weakRef_);
if (PictureInPictureManager::IsAutoStartControllerMapEmpty()) {
TLOGI(WmsLogTag::WMS_PIP, "autoStartControllerMap_ is empty, SetAutoStartEnabled false");
SetAutoStartEnabled(false);
}
}
WMError PictureInPictureController::ValidatePiPCreateParams(StartPipType startType)
{
if (pipOption_ == nullptr || pipOption_->GetContext() == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "Create pip failed, invalid pipOption");
SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
0, PipConst::FAILED, "Create pip failed, invalid pipOption");
return WMError::WM_ERROR_PIP_CREATE_FAILED;
}
mainWindowXComponentController_ = pipOption_->GetXComponentController();
if ((mainWindowXComponentController_ == nullptr && !IsTypeNodeEnabled()) || mainWindow_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "mainWindowXComponentController or mainWindow is nullptr");
SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
pipOption_->GetPipTemplate(), PipConst::FAILED, "mainWindowXComponentController or mainWindow is nullptr");
return WMError::WM_ERROR_PIP_CREATE_FAILED;
}
TLOGI(WmsLogTag::WMS_PIP, "mainWindow:%{public}u, mainWindowState:%{public}u",
mainWindowId_, mainWindow_->GetWindowState());
mainWindowLifeCycleListener_ = sptr<PictureInPictureController::WindowLifeCycleListener>::MakeSptr(mainWindowId_);
mainWindow_->RegisterLifeCycleListener(mainWindowLifeCycleListener_);
if (startType != StartPipType::AUTO_START && mainWindow_->GetWindowState() != WindowState::STATE_SHOWN) {
TLOGE(WmsLogTag::WMS_PIP, "mainWindow is not shown. create failed.");
SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
pipOption_->GetPipTemplate(), PipConst::FAILED, "mainWindow is not shown");
return WMError::WM_ERROR_PIP_CREATE_FAILED;
}
return WMError::WM_OK;
}
WMError PictureInPictureController::PreparePiPWindowCreation(StartPipType startType, PiPTemplateInfo& pipTemplateInfo,
std::shared_ptr<AbilityRuntime::Context>& abilityContext)
{
UpdateWinRectByComponent();
auto windowOption = sptr<WindowOption>::MakeSptr();
windowOption->SetWindowName(MakePipWindowName(createTimestamp_));
windowOption->SetWindowType(WindowType::WINDOW_TYPE_PIP);
windowOption->SetWindowMode(WindowMode::WINDOW_MODE_PIP);
windowOption->SetWindowRect(windowRect_);
windowOption->SetKeepScreenOn(true);
windowOption->SetTouchable(false);
WMError errCode = WMError::WM_OK;
pipOption_->GetPiPTemplateInfo(pipTemplateInfo);
pipTemplateInfo.createTimestamp = createTimestamp_;
auto context = static_cast<std::weak_ptr<AbilityRuntime::Context>*>(pipOption_->GetContext());
abilityContext = context->lock();
SingletonContainer::Get<PiPReporter>().SetCurrentPackageName(abilityContext->GetApplicationInfo()->name);
sptr<Window> window = FloatWindowManager::CreatePipWindow(windowOption, pipTemplateInfo, context->lock(), errCode);
if (window == nullptr || errCode != WMError::WM_OK) {
TLOGW(WmsLogTag::WMS_PIP, "Window create failed, reason: %{public}d", errCode);
SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
pipOption_->GetPipTemplate(), PipConst::FAILED, "Window create failed");
return errCode == WMError::WM_ERROR_FLOAT_CONFLICT_WITH_OTHERS ? errCode : WMError::WM_ERROR_PIP_CREATE_FAILED;
}
window_ = window;
window_->UpdatePiPRect(windowRect_, WindowSizeChangeReason::PIP_START);
PictureInPictureManager::PutPipControllerInfo(window_->GetWindowId(), this);
return WMError::WM_OK;
}
WMError PictureInPictureController::CreatePictureInPictureWindow(StartPipType startType)
{
auto ret = ValidatePiPCreateParams(startType);
if (ret != WMError::WM_OK) {
return ret;
}
PiPTemplateInfo pipTemplateInfo;
std::shared_ptr<AbilityRuntime::Context> abilityContext;
return PreparePiPWindowCreation(startType, pipTemplateInfo, abilityContext);
}
WMError PictureInPictureController::StartPictureInPicture(StartPipType startType)
{
TLOGI(WmsLogTag::WMS_PIP, "called");
if (pipOption_ == nullptr || pipOption_->GetContext() == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipOption is null or Get PictureInPictureOption failed");
SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
0, PipConst::FAILED, "pipOption is null or Get PictureInPictureOption failed");
return WMError::WM_ERROR_PIP_CREATE_FAILED;
}
if (curState_ == PiPWindowState::STATE_STARTING || curState_ == PiPWindowState::STATE_STARTED) {
TLOGW(WmsLogTag::WMS_PIP, "pipWindow is starting, state: %{public}u, id: %{public}u, mainWindow: %{public}u",
curState_, (window_ == nullptr) ? INVALID_WINDOW_ID : window_->GetWindowId(), mainWindowId_);
SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
pipOption_->GetPipTemplate(), PipConst::FAILED, "Pip window is starting");
return WMError::WM_ERROR_PIP_REPEAT_OPERATION;
}
if (!IsPullPiPAndHandleNavigation()) {
TLOGE(WmsLogTag::WMS_PIP, "Navigation operate failed");
SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
pipOption_->GetPipTemplate(), PipConst::FAILED, "Navigation operate failed");
return WMError::WM_ERROR_PIP_CREATE_FAILED;
}
curState_ = PiPWindowState::STATE_STARTING;
startTimestamp_ = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
bool reachLimit = PictureInPictureManager::IsPipGroupLimitReached(
static_cast<PiPTemplateType>(pipOption_->GetPipTemplate()));
if (reachLimit) {
window_ = PictureInPictureManager::GetSameGroupWindowByMainWindowId(mainWindowId_,
static_cast<PiPTemplateType>(pipOption_->GetPipTemplate()));
if (window_ != nullptr) {
TLOGI(WmsLogTag::WMS_PIP, "Reuse pipWindow: %{public}u as attached to the same mainWindow: %{public}u",
window_->GetWindowId(), mainWindowId_);
PictureInPictureManager::DoClose(window_->GetWindowId(), false, false);
mainWindowXComponentController_ = IsTypeNodeEnabled() ? nullptr : pipOption_->GetXComponentController();
UpdateWinRectByComponent();
UpdateContentSize(windowRect_.width_, windowRect_.height_);
PictureInPictureManager::PutPipControllerInfo(window_->GetWindowId(), this);
WMError err = ShowPictureInPictureWindow(startType);
if (err != WMError::WM_OK) {
curState_ = PiPWindowState::STATE_UNDEFINED;
} else {
curState_ = PiPWindowState::STATE_STARTED;
}
return err;
}
}
WMError errCode = StartPictureInPictureInner(startType);
if (errCode != WMError::WM_OK) {
DeletePIPMode();
}
return errCode;
}
void PictureInPictureController::SetAutoStartEnabled(bool enable)
{
TLOGI(WmsLogTag::WMS_PIP, "enable: %{public}u, mainWindow: %{public}u", enable, mainWindowId_);
isAutoStartEnabled_ = enable;
if (mainWindow_ == nullptr) {
return;
}
if (!pipOption_) {
TLOGE(WmsLogTag::WMS_PIP, "pipOption is null");
return;
}
uint32_t priority = pipOption_->GetPipPriority(pipOption_->GetPipTemplate());
uint32_t contentWidth = 0;
uint32_t contentHeight = 0;
pipOption_->GetContentSize(contentWidth, contentHeight);
if (isAutoStartEnabled_) {
if (!IsPullPiPAndHandleNavigation()) {
TLOGE(WmsLogTag::WMS_PIP, "Navigation operate failed");
isAutoStartEnabled_ = false;
mainWindow_->SetAutoStartPiP(false, priority, contentWidth, contentHeight);
return;
}
mainWindow_->SetAutoStartPiP(true, priority, contentWidth, contentHeight);
PictureInPictureManager::AttachAutoStartController(handleId_, weakRef_);
} else {
PictureInPictureManager::DetachAutoStartController(handleId_, weakRef_);
if (PictureInPictureManager::IsAutoStartControllerMapEmpty()) {
TLOGI(WmsLogTag::WMS_PIP, "autoStartControllerMap_ is empty, SetAutoStartEnabled false");
mainWindow_->SetAutoStartPiP(false, priority, contentWidth, contentHeight);
}
if (IsTypeNodeEnabled()) {
TLOGI(WmsLogTag::WMS_PIP, "typeNode enabled");
return;
}
std::string navId = pipOption_->GetNavigationId();
if (!navId.empty()) {
auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
if (navController) {
navController->DeletePIPMode(handleId_);
TLOGI(WmsLogTag::WMS_PIP, "Delete pip mode id: %{public}d", handleId_);
}
}
}
}
void PictureInPictureController::IsAutoStartEnabled(bool& enable) const
{
enable = isAutoStartEnabled_;
}
void PictureInPictureController::SetUIContent() const
{
napi_value storage = nullptr;
std::shared_ptr<NativeReference> storageRef = pipOption_->GetStorageRef();
if (storageRef != nullptr) {
storage = storageRef->GetNapiValue();
TLOGI(WmsLogTag::WMS_PIP, "startPiP with localStorage");
}
window_->SetUIContentByAbc(PIP_CONTENT_PATH, env_, storage, nullptr);
}
void PictureInPictureController::UpdateContentSize(int32_t width, int32_t height)
{
if (width <= 0 || height <= 0) {
TLOGE(WmsLogTag::WMS_PIP, "invalid size");
return;
}
if (pipOption_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipOption_ is nullptr");
return;
}
if (mainWindow_ != nullptr) {
TLOGI(WmsLogTag::WMS_PIP, "mainWindow width:%{public}u height:%{public}u", width, height);
uint32_t priority = pipOption_->GetPipPriority(pipOption_->GetPipTemplate());
uint32_t contentWidth = static_cast<uint32_t>(width);
uint32_t contentHeight = static_cast<uint32_t>(height);
mainWindow_->SetAutoStartPiP(isAutoStartEnabled_, priority, contentWidth, contentHeight);
}
pipOption_->SetContentSize(static_cast<uint32_t>(width), static_cast<uint32_t>(height));
if (curState_ != PiPWindowState::STATE_STARTED) {
TLOGD(WmsLogTag::WMS_PIP, "UpdateContentSize is disabled when state: %{public}u", curState_);
return;
}
if (window_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipWindow not exist");
return;
}
if (mainWindowXComponentController_ && !IsTypeNodeEnabled()) {
float posX = 0;
float posY = 0;
float newWidth = 0;
float newHeight = 0;
mainWindowXComponentController_->GetGlobalPosition(posX, posY);
mainWindowXComponentController_->GetSize(newWidth, newHeight);
bool isSizeChange = IsContentSizeChanged(newWidth, newHeight, posX, posY);
if (isSizeChange) {
Rect r = {static_cast<int32_t>(posX), static_cast<int32_t>(posY),
static_cast<uint32_t>(newWidth), static_cast<uint32_t>(newHeight)};
window_->UpdatePiPRect(r, WindowSizeChangeReason::TRANSFORM);
}
}
TLOGI(WmsLogTag::WMS_PIP, "window: %{public}u width:%{public}u height:%{public}u",
window_->GetWindowId(), width, height);
Rect rect = {0, 0, width, height};
window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RATIO_CHANGE);
SingletonContainer::Get<PiPReporter>().ReportPiPRatio(width, height);
}
void PictureInPictureController::UpdateContentNodeRef(std::shared_ptr<NativeReference> nodeRef)
{
TLOGI(WmsLogTag::WMS_PIP, "in");
if (pipOption_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "option is null");
SingletonContainer::Get<PiPReporter>().ReportPiPUpdateContent(static_cast<int32_t>(IsTypeNodeEnabled()),
0, PipConst::FAILED, "option is null");
return;
}
pipOption_->SetTypeNodeRef(nodeRef);
if (IsTypeNodeEnabled()) {
NotifyNodeUpdate(nodeRef);
return;
}
ResetExtController();
NotifyNodeUpdate(nodeRef);
if (isAutoStartEnabled_) {
std::string navId = pipOption_->GetNavigationId();
if (!navId.empty()) {
auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
if (navController) {
navController->DeletePIPMode(handleId_);
TLOGI(WmsLogTag::WMS_PIP, "Delete pip mode id: %{public}d", handleId_);
}
}
}
pipOption_->SetTypeNodeEnabled(true);
}
void PictureInPictureController::NotifyNodeUpdate(std::shared_ptr<NativeReference> nodeRef)
{
TLOGI(WmsLogTag::WMS_PIP, "in");
if (nodeRef == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "invalid nodeRef");
SingletonContainer::Get<PiPReporter>().ReportPiPUpdateContent(static_cast<int32_t>(IsTypeNodeEnabled()),
pipOption_->GetPipTemplate(), PipConst::FAILED, "invalid nodeRef");
return;
}
if (PictureInPictureManager::IsActiveController(weakRef_)) {
std::shared_ptr<NativeReference> updateNodeCallbackRef = GetPipContentCallbackRef(UPDATE_NODE);
if (updateNodeCallbackRef == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "updateNodeCallbackRef is null");
SingletonContainer::Get<PiPReporter>().ReportPiPUpdateContent(static_cast<int32_t>(IsTypeNodeEnabled()),
pipOption_->GetPipTemplate(), PipConst::FAILED, "updateNodeCallbackRef is null");
return;
}
napi_value typeNode = nodeRef->GetNapiValue();
napi_value value[] = { typeNode };
CallJsFunction(env_, updateNodeCallbackRef->GetNapiValue(), value, 1);
SingletonContainer::Get<PiPReporter>().ReportPiPUpdateContent(static_cast<int32_t>(IsTypeNodeEnabled()),
pipOption_->GetPipTemplate(), PipConst::PIP_SUCCESS, "updateNode success");
}
}
void PictureInPictureController::PrepareSource()
{
TLOGI(WmsLogTag::WMS_PIP, "in");
if (IsTypeNodeEnabled()) {
TLOGI(WmsLogTag::WMS_PIP, "typeNode enabled");
return;
}
if (mainWindow_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "mainWindow is nullptr");
return;
}
std::string navId = pipOption_->GetNavigationId();
if (navId != "") {
auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
if (navController) {
navController->PushInPIP(handleId_);
TLOGI(WmsLogTag::WMS_PIP, "Push in pip handleId: %{public}d", handleId_);
} else {
TLOGE(WmsLogTag::WMS_PIP, "navController is nullptr");
}
}
}
void PictureInPictureController::RestorePictureInPictureWindow()
{
StopPictureInPicture(true, StopPipType::NULL_STOP, true);
SingletonContainer::Get<PiPReporter>().ReportPiPRestore();
TLOGI(WmsLogTag::WMS_PIP, "restore pip main window finished");
}
void PictureInPictureController::UpdateWinRectByComponent()
{
if (IsTypeNodeEnabled()) {
uint32_t contentWidth = 0;
uint32_t contentHeight = 0;
pipOption_->GetContentSize(contentWidth, contentHeight);
if (contentWidth == 0 || contentHeight == 0) {
contentWidth = PipConst::DEFAULT_ASPECT_RATIOS[0];
contentHeight = PipConst::DEFAULT_ASPECT_RATIOS[1];
}
windowRect_.posX_ = 0;
windowRect_.posY_ = 0;
windowRect_.width_ = contentWidth;
windowRect_.height_ = contentHeight;
return;
}
if (!mainWindowXComponentController_) {
TLOGE(WmsLogTag::WMS_PIP, "main window xComponent not set");
return;
}
float posX = 0;
float posY = 0;
float width = 0;
float height = 0;
mainWindowXComponentController_->GetGlobalPosition(posX, posY);
mainWindowXComponentController_->GetSize(width, height);
windowRect_.width_ = static_cast<uint32_t>(width);
windowRect_.height_ = static_cast<uint32_t>(height);
if (windowRect_.width_ == 0 || windowRect_.height_ == 0) {
uint32_t contentWidth = 0;
uint32_t contentHeight = 0;
pipOption_->GetContentSize(contentWidth, contentHeight);
windowRect_.width_ = contentWidth;
windowRect_.height_ = contentHeight;
}
windowRect_.posX_ = static_cast<int32_t>(posX);
windowRect_.posY_ = static_cast<int32_t>(posY);
TLOGD(WmsLogTag::WMS_PIP, "position width: %{public}u, height: %{public}u, posX: %{public}d, posY: %{public}d",
windowRect_.width_, windowRect_.height_, windowRect_.posX_, windowRect_.posY_);
}
void PictureInPictureController::UpdatePiPSourceRect() const
{
if (IsTypeNodeEnabled() && window_ != nullptr) {
Rect rect = {0, 0, 0, 0};
TLOGI(WmsLogTag::WMS_PIP, "use typeNode, unable to locate source rect");
window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RESTORE);
return;
}
if (mainWindowXComponentController_ == nullptr || window_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "xcomponent controller not valid");
return;
}
float posX = 0;
float posY = 0;
float width = 0;
float height = 0;
mainWindowXComponentController_->GetGlobalPosition(posX, posY);
mainWindowXComponentController_->GetSize(width, height);
Rect rect = { posX, posY, width, height };
TLOGI(WmsLogTag::WMS_PIP, "result rect: [%{public}d, %{public}d, %{public}u, %{public}u]",
rect.posX_, rect.posY_, rect.width_, rect.height_);
window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RESTORE);
}
void PictureInPictureController::ResetExtController()
{
TLOGI(WmsLogTag::WMS_PIP, "called");
if (IsTypeNodeEnabled()) {
TLOGI(WmsLogTag::WMS_PIP, "skip resetExtController as nodeController enabled");
return;
}
if (mainWindowXComponentController_ == nullptr || pipXComponentController_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "error when resetExtController, one of the xComponentController is null");
return;
}
XComponentControllerErrorCode errorCode =
mainWindowXComponentController_->ResetExtController(pipXComponentController_);
if (errorCode != XComponentControllerErrorCode::XCOMPONENT_CONTROLLER_NO_ERROR) {
TLOGE(WmsLogTag::WMS_PIP, "swap xComponent failed, errorCode: %{public}u", errorCode);
}
}
WMError PictureInPictureController::SetXComponentController(std::shared_ptr<XComponentController> xComponentController)
{
TLOGI(WmsLogTag::WMS_PIP, "called");
if (IsTypeNodeEnabled()) {
TLOGI(WmsLogTag::WMS_PIP, "skip as nodeController enabled");
return WMError::WM_OK;
}
pipXComponentController_ = xComponentController;
if (window_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "window is nullptr when set XComponentController");
return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
}
if (mainWindowXComponentController_ == nullptr || pipXComponentController_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "error when setXController, one of the xComponentController is null");
return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
}
XComponentControllerErrorCode errorCode =
mainWindowXComponentController_->SetExtController(pipXComponentController_);
if (errorCode != XComponentControllerErrorCode::XCOMPONENT_CONTROLLER_NO_ERROR) {
TLOGE(WmsLogTag::WMS_PIP, "swap xComponent failed, errorCode: %{public}u", errorCode);
return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
}
OnPictureInPictureStart();
return WMError::WM_OK;
}
WMError PictureInPictureController::RegisterPipContentListenerWithType(const std::string& type,
std::shared_ptr<NativeReference> callbackRef)
{
TLOGI(WmsLogTag::WMS_PIP, "Register type:%{public}s", type.c_str());
if (pipOption_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "Get PictureInPicture option failed");
return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
}
pipOption_->RegisterPipContentListenerWithType(type, callbackRef);
return WMError::WM_OK;
}
WMError PictureInPictureController::UnRegisterPipContentListenerWithType(const std::string& type)
{
TLOGI(WmsLogTag::WMS_PIP, "Unregister type:%{public}s", type.c_str());
if (pipOption_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "Get PictureInPicture option failed");
return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
}
pipOption_->UnRegisterPipContentListenerWithType(type);
return WMError::WM_OK;
}
std::shared_ptr<NativeReference> PictureInPictureController::GetPipContentCallbackRef(const std::string& type)
{
return pipOption_ == nullptr ? nullptr : pipOption_->GetPipContentCallbackRef(type);
}
void PictureInPictureController::NotifyStateChangeInner(PiPState state)
{
NotifyStateChangeInner(env_, state);
}
void PictureInPictureController::NotifyStateChangeInner(napi_env env, PiPState state)
{
std::shared_ptr<NativeReference> innerCallbackRef = GetPipContentCallbackRef(STATE_CHANGE_WM);
if (innerCallbackRef == nullptr) {
return;
}
napi_handle_scope scope = nullptr;
napi_open_handle_scope(env, &scope);
if (scope == nullptr) {
return;
}
napi_value value[] = {AbilityRuntime::CreateJsValue(env, static_cast<uint32_t>(state))};
CallJsFunction(env, innerCallbackRef->GetNapiValue(), value, 1);
napi_close_handle_scope(env, scope);
}
bool PictureInPictureController::IsTypeNodeEnabled() const
{
return pipOption_ != nullptr ? pipOption_->IsTypeNodeEnabled() : false;
}
bool PictureInPictureController::IsPullPiPAndHandleNavigation()
{
if (IsTypeNodeEnabled()) {
TLOGI(WmsLogTag::WMS_PIP, "App use typeNode");
return true;
}
if (pipOption_->GetNavigationId() == "") {
TLOGI(WmsLogTag::WMS_PIP, "App not use navigation");
return true;
}
if (mainWindow_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "Main window init error");
return false;
}
std::string navId = pipOption_->GetNavigationId();
int32_t pipOptionHandleId = pipOption_->GetHandleId();
auto navController = GetNavigationController(navId);
if (navController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "Get navController error");
return false;
}
if (pipOptionHandleId != INVALID_HANDLE_ID) {
navController->SetInPIPMode(pipOptionHandleId);
handleId_ = pipOptionHandleId;
TLOGI(WmsLogTag::WMS_PIP, "SetInPIPMode handleId_: %{public}d, top result: %{public}d",
handleId_, navController->GetTopHandle());
return true;
}
if (!navController->IsNavDestinationInTopStack()) {
TLOGE(WmsLogTag::WMS_PIP, "Top is not navDestination");
return false;
}
TLOGI(WmsLogTag::WMS_PIP, "IsNavDestinationInTopStack: true");
handleId_ = navController->GetTopHandle();
if (handleId_ == INVALID_HANDLE_ID) {
TLOGE(WmsLogTag::WMS_PIP, "Get top handle error");
return false;
}
if (firstHandleId_ != INVALID_HANDLE_ID) {
handleId_ = firstHandleId_;
navController->SetInPIPMode(handleId_);
TLOGI(WmsLogTag::WMS_PIP, "Cache first navigation");
} else {
TLOGI(WmsLogTag::WMS_PIP, "First top handle id: %{public}d", handleId_);
firstHandleId_ = handleId_;
navController->SetInPIPMode(handleId_);
}
return true;
}
std::string PictureInPictureController::GetPiPNavigationId() const
{
return (pipOption_ != nullptr && !IsTypeNodeEnabled()) ? pipOption_->GetNavigationId() : "";
}
std::shared_ptr<NativeReference> PictureInPictureController::GetCustomNodeController()
{
return pipOption_ == nullptr ? nullptr : pipOption_->GetNodeControllerRef();
}
std::shared_ptr<NativeReference> PictureInPictureController::GetTypeNode() const
{
return pipOption_ == nullptr ? nullptr : pipOption_->GetTypeNodeRef();
}
NavigationController* PictureInPictureController::GetNavigationController(const std::string& navId)
{
return NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
}
void PictureInPictureController::DeletePIPMode()
{
if (mainWindow_ == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "Main window is null");
return;
}
std::string navId = pipOption_->GetNavigationId();
if (!navId.empty()) {
auto navController = GetNavigationController(navId);
if (navController) {
navController->DeletePIPMode(handleId_);
TLOGI(WmsLogTag::WMS_PIP, "Delete pip mode id: %{public}d", handleId_);
}
}
}
}
}