* Copyright (c) 2025 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 "oh_window_pip.h"
#include "oh_window_comm.h"
#include "web_picture_in_picture_controller_interface.h"
#include "window_manager_hilog.h"
using namespace OHOS::Rosen;
namespace OHOS {
namespace Rosen {
namespace {
constexpr uint32_t MAX_CONTROL_TYPE_NUM = 8;
constexpr uint32_t MAX_CONTROL_STATUS_NUM = 1;
std::shared_mutex idMapMutex_;
std::map<uint32_t, sptr<WebPictureInPictureControllerInterface>> g_ControllerIds;
}
inline bool IsIdMapFull()
{
std::shared_lock<std::shared_mutex> lock(idMapMutex_);
if (g_ControllerIds.size() >= static_cast<size_t>(UINT32_MAX - 1)) {
return true;
}
return false;
}
inline uint32_t FindNextAvailableId()
{
if (IsIdMapFull()) {
return 0;
}
uint32_t nextId = 0;
std::unique_lock<std::shared_mutex> lock(idMapMutex_);
while (nextId < UINT32_MAX && g_ControllerIds.find(nextId) != g_ControllerIds.end()) {
nextId++;
}
return nextId;
}
inline sptr<WebPictureInPictureControllerInterface> GetControllerFromId(uint32_t controllerId)
{
std::shared_lock<std::shared_mutex> lock(idMapMutex_);
if (g_ControllerIds.find(controllerId) == g_ControllerIds.end()) {
return nullptr;
}
return g_ControllerIds.at(controllerId);
}
}
}
namespace {
* Used to map from WMError to WindowManager_ErrorCode.
*/
const std::unordered_map<WMError, WindowManager_ErrorCode> OH_WINDOW_TO_ERROR_CODE_MAP {
{ WMError::WM_OK, WindowManager_ErrorCode::OK },
{ WMError::WM_ERROR_INVALID_PARAM, WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM },
{ WMError::WM_ERROR_DEVICE_NOT_SUPPORT, WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_DEVICE_NOT_SUPPORTED },
{ WMError::WM_ERROR_PIP_DESTROY_FAILED, WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_PIP_DESTROY_FAILED },
{ WMError::WM_ERROR_PIP_STATE_ABNORMALLY, WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_PIP_STATE_ABNORMAL },
{ WMError::WM_ERROR_PIP_CREATE_FAILED, WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_PIP_CREATE_FAILED },
{ WMError::WM_ERROR_PIP_INTERNAL_ERROR, WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_PIP_INTERNAL_ERROR },
{ WMError::WM_ERROR_PIP_REPEAT_OPERATION,
WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_PIP_REPEATED_OPERATION },
};
inline WindowManager_ErrorCode GetErrorCodeFromWMError(WMError error)
{
if (OH_WINDOW_TO_ERROR_CODE_MAP.find(error) == OH_WINDOW_TO_ERROR_CODE_MAP.end()) {
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_PIP_INTERNAL_ERROR;
}
return OH_WINDOW_TO_ERROR_CODE_MAP.at(error);
}
}
int32_t OH_PictureInPicture_CreatePipConfig(PictureInPicture_PipConfig* pipConfig)
{
if (pipConfig == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipConfig is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
PiPConfig* config = new PiPConfig();
*pipConfig = reinterpret_cast<PictureInPicture_PipConfig>(config);
TLOGI(WmsLogTag::WMS_PIP, "pipConfig created");
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_DestroyPipConfig(PictureInPicture_PipConfig* pipConfig)
{
if (pipConfig == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipConfig is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto config = reinterpret_cast<PiPConfig*>(*pipConfig);
delete config;
*pipConfig = nullptr;
TLOGI(WmsLogTag::WMS_PIP, "pipConfig destroyed");
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_SetPipMainWindowId(PictureInPicture_PipConfig pipConfig, uint32_t mainWindowId)
{
if (pipConfig == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipConfig is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto config = reinterpret_cast<PiPConfig*>(pipConfig);
config->mainWindowId = mainWindowId;
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_SetPipTemplateType(PictureInPicture_PipConfig pipConfig,
PictureInPicture_PipTemplateType pipTemplateType)
{
if (pipConfig == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipConfig is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto config = reinterpret_cast<PiPConfig*>(pipConfig);
config->pipTemplateType = static_cast<uint32_t>(pipTemplateType);
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_SetPipRect(PictureInPicture_PipConfig pipConfig, uint32_t width, uint32_t height)
{
if (pipConfig == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipConfig is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto config = reinterpret_cast<PiPConfig*>(pipConfig);
config->width = width;
config->height = height;
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_SetPipControlGroup(PictureInPicture_PipConfig pipConfig,
PictureInPicture_PipControlGroup* controlGroup, uint8_t controlGroupLength)
{
if (pipConfig == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipConfig is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto config = reinterpret_cast<PiPConfig*>(pipConfig);
if (controlGroup != nullptr) {
config->controlGroup = std::vector<uint32_t>(controlGroup, controlGroup + controlGroupLength);
} else {
config->controlGroup = {};
}
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_SetPipNapiEnv(PictureInPicture_PipConfig pipConfig, void* env)
{
if (pipConfig == nullptr || env == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipConfig or env is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto config = reinterpret_cast<PiPConfig*>(pipConfig);
config->env = reinterpret_cast<napi_env>(env);
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_CreatePip(PictureInPicture_PipConfig pipConfig, uint32_t* controllerId)
{
if (pipConfig == nullptr || controllerId == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "pipConfig or controllerId is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
if (IsIdMapFull()) {
TLOGE(WmsLogTag::WMS_PIP, "all IDs are used");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_PIP_INTERNAL_ERROR;
}
auto config = reinterpret_cast<PiPConfig*>(pipConfig);
auto webPipControllerInterface = OHOS::sptr<WebPictureInPictureControllerInterface>::MakeSptr();
auto errCode = webPipControllerInterface->Create(*config);
if (errCode != WMError::WM_OK) {
TLOGE(WmsLogTag::WMS_PIP, "pipInterface create failed");
return GetErrorCodeFromWMError(errCode);
}
uint32_t id = FindNextAvailableId();
*controllerId = id;
std::unique_lock<std::shared_mutex> lock(idMapMutex_);
g_ControllerIds[id] = webPipControllerInterface;
TLOGI(WmsLogTag::WMS_PIP, "create success! controllerId: %{public}u", id);
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_DeletePip(uint32_t controllerId)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
if (pipController->IsStarted()) {
TLOGE(WmsLogTag::WMS_PIP, "could not delete before stopPip: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
std::unique_lock<std::shared_mutex> lock(idMapMutex_);
g_ControllerIds.erase(controllerId);
return WindowManager_ErrorCode::OK;
}
int32_t OH_PictureInPicture_StartPip(uint32_t controllerId)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->StartPip(controllerId));
}
int32_t OH_PictureInPicture_StopPip(uint32_t controllerId)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->StopPip());
}
int32_t OH_PictureInPicture_UpdatePipContentSize(uint32_t controllerId, uint32_t width, uint32_t height)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UpdateContentSize(width, height));
}
int32_t OH_PictureInPicture_UpdatePipControlStatus(uint32_t controllerId, PictureInPicture_PipControlType controlType,
PictureInPicture_PipControlStatus status)
{
auto typeNum = static_cast<uint32_t>(controlType);
auto statusNum = static_cast<uint32_t>(status);
if (typeNum > MAX_CONTROL_TYPE_NUM || statusNum > MAX_CONTROL_STATUS_NUM) {
TLOGE(WmsLogTag::WMS_PIP, "param error. controlType: %{public}d, status: %{public}d", typeNum, statusNum);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UpdatePiPControlStatus(static_cast<PiPControlType>(controlType),
static_cast<PiPControlStatus>(status)));
}
int32_t OH_PictureInPicture_SetPipControlEnabled(uint32_t controllerId, PictureInPicture_PipControlType controlType,
bool enabled)
{
auto typeNum = static_cast<uint32_t>(controlType);
if (typeNum > MAX_CONTROL_TYPE_NUM) {
TLOGE(WmsLogTag::WMS_PIP, "param error. controlType: %{public}d", typeNum);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->setPiPControlEnabled(static_cast<PiPControlType>(controlType),
enabled));
}
int32_t OH_PictureInPicture_SetParentWindowId(uint32_t controllerId, uint32_t windowId)
{
if (windowId <= 0) {
TLOGE(WmsLogTag::WMS_PIP, "windowId invalid: %{public}d", windowId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->SetPipParentWindowId(windowId));
}
int32_t OH_PictureInPicture_SetPipInitialSurfaceRect(uint32_t controllerId, int32_t positionX, int32_t positionY,
uint32_t width, uint32_t height)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->SetPipInitialSurfaceRect(positionX, positionY, width, height));
}
int32_t OH_PictureInPicture_UnsetPipInitialSurfaceRect(uint32_t controllerId)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnsetPipInitialSurfaceRect());
}
int32_t OH_PictureInPicture_RegisterStartPipCallback(uint32_t controllerId, WebPipStartPipCallback callback)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->RegisterStartPipListener(callback));
}
int32_t OH_PictureInPicture_UnregisterStartPipCallback(uint32_t controllerId, WebPipStartPipCallback callback)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
if (callback == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "callback is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnregisterStartPipListener(callback));
}
int32_t OH_PictureInPicture_UnregisterAllStartPipCallbacks(uint32_t controllerId)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnregisterAllPiPStart());
}
int32_t OH_PictureInPicture_RegisterLifecycleListener(uint32_t controllerId, WebPipLifecycleCallback callback)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->RegisterLifeCycleListener(
reinterpret_cast<OHOS::Rosen::NativePipLifeCycleCallback>(callback)));
}
int32_t OH_PictureInPicture_UnregisterLifecycleListener(uint32_t controllerId, WebPipLifecycleCallback callback)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
if (callback == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "callback is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnregisterLifeCycleListener(
reinterpret_cast<OHOS::Rosen::NativePipLifeCycleCallback>(callback)));
}
int32_t OH_PictureInPicture_UnregisterAllLifecycleListeners(uint32_t controllerId)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnregisterAllPiPLifecycle());
}
int32_t OH_PictureInPicture_RegisterControlEventListener(uint32_t controllerId, WebPipControlEventCallback callback)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->RegisterControlEventListener(
reinterpret_cast<OHOS::Rosen::NativePipControlEventCallback>(callback)));
}
int32_t OH_PictureInPicture_UnregisterControlEventListener(uint32_t controllerId, WebPipControlEventCallback callback)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
if (callback == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "callback is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnregisterControlEventListener(
reinterpret_cast<OHOS::Rosen::NativePipControlEventCallback>(callback)));
}
int32_t OH_PictureInPicture_UnregisterAllControlEventListeners(uint32_t controllerId)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnregisterAllPiPControlObserver());
}
int32_t OH_PictureInPicture_RegisterResizeListener(uint32_t controllerId, WebPipResizeCallback callback)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->RegisterResizeListener(callback));
}
int32_t OH_PictureInPicture_UnregisterResizeListener(uint32_t controllerId, WebPipResizeCallback callback)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
if (callback == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "callback is nullptr");
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnregisterResizeListener(callback));
}
int32_t OH_PictureInPicture_UnregisterAllResizeListeners(uint32_t controllerId)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->UnregisterAllPiPWindowSize());
}
int32_t OH_PictureInPicture_SetAutoStartEnabled(uint32_t controllerId, bool enabled)
{
auto pipController = GetControllerFromId(controllerId);
if (pipController == nullptr) {
TLOGE(WmsLogTag::WMS_PIP, "controllerId not found: %{public}d", controllerId);
return WindowManager_ErrorCode::WINDOW_MANAGER_ERRORCODE_INCORRECT_PARAM;
}
return GetErrorCodeFromWMError(pipController->SetPipAutoStartEnabled(enabled));
}