/* * Copyright (c) 2021-2022 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 "screen_manager.h" #include #include #include #include "display_manager_adapter.h" #include "display_manager_agent_default.h" #include "singleton_delegator.h" #include "window_manager_hilog.h" namespace OHOS::Rosen { namespace { constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "ScreenManager"}; const static uint32_t MAX_SCREEN_SIZE = 32; } class ScreenManager::Impl : public RefBase { public: Impl() = default; ~Impl(); static inline SingletonDelegator delegator; bool RegisterScreenListener(sptr listener); bool UnregisterScreenListener(sptr listener); bool RegisterScreenGroupListener(sptr listener); bool UnregisterScreenGroupListener(sptr listener); sptr GetScreen(ScreenId screenId); sptr GetScreenGroup(ScreenId screenId); std::vector> GetAllScreens(); private: void NotifyScreenConnect(sptr info); void NotifyScreenDisconnect(ScreenId); void NotifyScreenChange(const sptr& screenInfo); void NotifyScreenChange(const std::vector>& screenInfos); bool UpdateScreenInfoLocked(sptr); class ScreenManagerListener; sptr screenManagerListener_; std::map> screenMap_; std::map> screenGroupMap_; std::recursive_mutex mutex_; std::set> screenListeners_; std::set> screenGroupListeners_; }; class ScreenManager::Impl::ScreenManagerListener : public DisplayManagerAgentDefault { public: ScreenManagerListener(sptr impl) : pImpl_(impl) { } void OnScreenConnect(sptr screenInfo) { if (screenInfo == nullptr || screenInfo->GetScreenId() == SCREEN_ID_INVALID) { WLOGFE("OnScreenConnect, screenInfo is invalid."); return; } if (pImpl_ == nullptr) { WLOGFE("OnScreenConnect, impl is nullptr."); return; } pImpl_->NotifyScreenConnect(screenInfo); for (auto listener : pImpl_->screenListeners_) { listener->OnConnect(screenInfo->GetScreenId()); } }; void OnScreenDisconnect(ScreenId screenId) { if (screenId == SCREEN_ID_INVALID) { WLOGFE("OnScreenDisconnect, screenId is invalid."); return; } if (pImpl_ == nullptr) { WLOGFE("OnScreenDisconnect, impl is nullptr."); return; } pImpl_->NotifyScreenDisconnect(screenId); for (auto listener : pImpl_->screenListeners_) { listener->OnDisconnect(screenId); } }; void OnScreenChange(const sptr& screenInfo, ScreenChangeEvent event) { if (screenInfo == nullptr) { WLOGFE("OnScreenChange, screenInfo is null."); return; } if (pImpl_ == nullptr) { WLOGFE("OnScreenChange, impl is nullptr."); return; } WLOGFD("OnScreenChange. event %{public}u", event); pImpl_->NotifyScreenChange(screenInfo); for (auto listener: pImpl_->screenListeners_) { listener->OnChange(screenInfo->GetScreenId()); } }; void OnScreenGroupChange(const std::vector>& screenInfos, ScreenGroupChangeEvent groupEvent) { if (screenInfos.empty()) { WLOGFE("OnScreenGroupChange, screenInfos is empty."); return; } if (pImpl_ == nullptr) { WLOGFE("OnScreenGroupChange, impl is nullptr."); return; } WLOGFD("OnScreenGroupChange. event %{public}u", groupEvent); pImpl_->NotifyScreenChange(screenInfos); std::vector screenIds; for (auto screenInfo : screenInfos) { if (screenInfo->GetScreenId() != SCREEN_ID_INVALID) { screenIds.push_back(screenInfo->GetScreenId()); } } for (auto listener: pImpl_->screenGroupListeners_) { listener->OnChange(screenIds, groupEvent); } }; private: sptr pImpl_; }; WM_IMPLEMENT_SINGLE_INSTANCE(ScreenManager) ScreenManager::ScreenManager() { pImpl_ = new Impl(); } ScreenManager::~ScreenManager() { } ScreenManager::Impl::~Impl() { std::lock_guard lock(mutex_); bool res = true; if (screenManagerListener_ != nullptr) { res = SingletonContainer::Get().UnregisterDisplayManagerAgent( screenManagerListener_, DisplayManagerAgentType::SCREEN_EVENT_LISTENER); } screenManagerListener_ = nullptr; if (!res) { WLOGFW("UnregisterDisplayManagerAgent SCREEN_EVENT_LISTENER failed !"); } } sptr ScreenManager::Impl::GetScreen(ScreenId screenId) { auto screenInfo = SingletonContainer::Get().GetScreenInfo(screenId); std::lock_guard lock(mutex_); if (!UpdateScreenInfoLocked(screenInfo)) { screenMap_.erase(screenId); return nullptr; } return screenMap_[screenId]; } sptr ScreenManager::GetScreenById(ScreenId screenId) { return pImpl_->GetScreen(screenId); } sptr ScreenManager::Impl::GetScreenGroup(ScreenId screenId) { auto screenGroupInfo = SingletonContainer::Get().GetScreenGroupInfoById(screenId); std::lock_guard lock(mutex_); if (screenGroupInfo == nullptr) { WLOGFE("screenGroupInfo is null"); screenGroupMap_.erase(screenId); return nullptr; } auto iter = screenGroupMap_.find(screenId); if (iter != screenGroupMap_.end() && iter->second != nullptr) { WLOGFI("get screenGroup in screenGroup map"); iter->second->UpdateScreenGroupInfo(screenGroupInfo); return iter->second; } sptr screenGroup = new ScreenGroup(screenGroupInfo); screenGroupMap_[screenId] = screenGroup; return screenGroup; } sptr ScreenManager::GetScreenGroup(ScreenId screenId) { return pImpl_->GetScreenGroup(screenId); } std::vector> ScreenManager::Impl::GetAllScreens() { auto screenInfos = SingletonContainer::Get().GetAllScreenInfos(); std::vector> screens; std::lock_guard lock(mutex_); for (auto info: screenInfos) { if (UpdateScreenInfoLocked(info)) { screens.emplace_back(screenMap_[info->GetScreenId()]); } } screenMap_.clear(); for (auto screen: screens) { screenMap_.insert(std::make_pair(screen->GetId(), screen)); } return screens; } std::vector> ScreenManager::GetAllScreens() { return pImpl_->GetAllScreens(); } bool ScreenManager::Impl::RegisterScreenListener(sptr listener) { std::lock_guard lock(mutex_); bool ret = true; if (screenManagerListener_ == nullptr) { screenManagerListener_ = new ScreenManagerListener(this); ret = SingletonContainer::Get().RegisterDisplayManagerAgent( screenManagerListener_, DisplayManagerAgentType::SCREEN_EVENT_LISTENER); } if (!ret) { WLOGFW("RegisterScreenListener failed !"); screenManagerListener_ = nullptr; } else { screenListeners_.insert(listener); } return ret; } bool ScreenManager::RegisterScreenListener(sptr listener) { if (listener == nullptr) { WLOGFE("RegisterScreenListener listener is nullptr."); return false; } return pImpl_->RegisterScreenListener(listener); } bool ScreenManager::Impl::UnregisterScreenListener(sptr listener) { std::lock_guard lock(mutex_); auto iter = std::find(screenListeners_.begin(), screenListeners_.end(), listener); if (iter == screenListeners_.end()) { WLOGFE("could not find this listener"); return false; } bool ret = true; screenListeners_.erase(iter); if (screenListeners_.empty() && screenGroupListeners_.empty() && screenManagerListener_ != nullptr) { ret = SingletonContainer::Get().UnregisterDisplayManagerAgent( screenManagerListener_, DisplayManagerAgentType::SCREEN_EVENT_LISTENER); screenManagerListener_ = nullptr; } return ret; } bool ScreenManager::UnregisterScreenListener(sptr listener) { if (listener == nullptr) { WLOGFE("UnregisterScreenListener listener is nullptr."); return false; } return pImpl_->UnregisterScreenListener(listener); } bool ScreenManager::Impl::RegisterScreenGroupListener(sptr listener) { std::lock_guard lock(mutex_); bool ret = true; if (screenManagerListener_ == nullptr) { screenManagerListener_ = new ScreenManagerListener(this); ret = SingletonContainer::Get().RegisterDisplayManagerAgent( screenManagerListener_, DisplayManagerAgentType::SCREEN_EVENT_LISTENER); } if (!ret) { WLOGFW("RegisterScreenGroupListener failed !"); screenManagerListener_ = nullptr; } else { screenGroupListeners_.insert(listener); } return ret; } bool ScreenManager::RegisterScreenGroupListener(sptr listener) { if (listener == nullptr) { WLOGFE("RegisterScreenGroupListener listener is nullptr."); return false; } return pImpl_->RegisterScreenGroupListener(listener); } bool ScreenManager::Impl::UnregisterScreenGroupListener(sptr listener) { std::lock_guard lock(mutex_); auto iter = std::find(screenGroupListeners_.begin(), screenGroupListeners_.end(), listener); if (iter == screenGroupListeners_.end()) { WLOGFE("could not find this listener"); return false; } bool ret = true; screenGroupListeners_.erase(iter); if (screenGroupListeners_.empty() && screenGroupListeners_.empty() && screenManagerListener_ != nullptr) { ret = SingletonContainer::Get().UnregisterDisplayManagerAgent( screenManagerListener_, DisplayManagerAgentType::SCREEN_EVENT_LISTENER); screenManagerListener_ = nullptr; } return ret; } bool ScreenManager::UnregisterScreenGroupListener(sptr listener) { if (listener == nullptr) { WLOGFE("UnregisterScreenGroupListener listener is nullptr."); return false; } return pImpl_->UnregisterScreenGroupListener(listener); } ScreenId ScreenManager::MakeExpand(const std::vector& options) { WLOGFI("Make expand"); if (options.empty()) { return SCREEN_ID_INVALID; } if (options.size() > MAX_SCREEN_SIZE) { WLOGFW("Make expand failed. The options size is bigger than %{public}u.", MAX_SCREEN_SIZE); return SCREEN_ID_INVALID; } std::vector screenIds; std::vector startPoints; for (auto& option: options) { if (std::find(screenIds.begin(), screenIds.end(), option.screenId_) != screenIds.end()) { continue; } screenIds.emplace_back(option.screenId_); startPoints.emplace_back(Point(option.startX_, option.startY_)); } ScreenId group = SingletonContainer::Get().MakeExpand(screenIds, startPoints); if (group == SCREEN_ID_INVALID) { WLOGFI("Make expand failed"); } return group; } ScreenId ScreenManager::MakeMirror(ScreenId mainScreenId, std::vector mirrorScreenId) { WLOGFI("create mirror for screen: %{public}" PRIu64"", mainScreenId); if (mirrorScreenId.size() > MAX_SCREEN_SIZE) { WLOGFW("Make Mirror failed. The mirrorScreenId size is bigger than %{public}u.", MAX_SCREEN_SIZE); return SCREEN_ID_INVALID; } ScreenId group = SingletonContainer::Get().MakeMirror(mainScreenId, mirrorScreenId); if (group == SCREEN_ID_INVALID) { WLOGFI("create mirror failed"); } return group; } void ScreenManager::RemoveVirtualScreenFromGroup(std::vector screens) { if (screens.empty()) { WLOGFW("RemoveVirtualScreenFromGroup failed. screens is empty."); return; } if (screens.size() > MAX_SCREEN_SIZE) { WLOGFW("RemoveVirtualScreenFromGroup failed. The screens size is bigger than %{public}u.", MAX_SCREEN_SIZE); return; } SingletonContainer::Get().RemoveVirtualScreenFromGroup(screens); } ScreenId ScreenManager::CreateVirtualScreen(VirtualScreenOption option) { return SingletonContainer::Get().CreateVirtualScreen(option); } DMError ScreenManager::DestroyVirtualScreen(ScreenId screenId) { return SingletonContainer::Get().DestroyVirtualScreen(screenId); } DMError ScreenManager::SetVirtualScreenSurface(ScreenId screenId, sptr surface) { return SingletonContainer::Get().SetVirtualScreenSurface(screenId, surface); } bool ScreenManager::SetScreenPowerForAll(ScreenPowerState state, PowerStateChangeReason reason) { WLOGFI("state:%{public}u, reason:%{public}u", state, reason); return SingletonContainer::Get().SetScreenPowerForAll(state, reason); } ScreenPowerState ScreenManager::GetScreenPower(ScreenId dmsScreenId) { return SingletonContainer::Get().GetScreenPower(dmsScreenId); } void ScreenManager::Impl::NotifyScreenConnect(sptr info) { std::lock_guard lock(mutex_); UpdateScreenInfoLocked(info); } void ScreenManager::Impl::NotifyScreenDisconnect(ScreenId screenId) { WLOGFI("screenId:%{public}" PRIu64".", screenId); std::lock_guard lock(mutex_); screenMap_.erase(screenId); } void ScreenManager::Impl::NotifyScreenChange(const sptr& screenInfo) { std::lock_guard lock(mutex_); UpdateScreenInfoLocked(screenInfo); } void ScreenManager::Impl::NotifyScreenChange(const std::vector>& screenInfos) { std::lock_guard lock(mutex_); for (auto screenInfo : screenInfos) { UpdateScreenInfoLocked(screenInfo); } } bool ScreenManager::Impl::UpdateScreenInfoLocked(sptr screenInfo) { if (screenInfo == nullptr) { WLOGFE("displayInfo is null"); return false; } ScreenId screenId = screenInfo->GetScreenId(); WLOGFI("screenId:%{public}" PRIu64".", screenId); if (screenId == SCREEN_ID_INVALID) { WLOGFE("displayId is invalid."); return false; } auto iter = screenMap_.find(screenId); if (iter != screenMap_.end() && iter->second != nullptr) { WLOGFI("get screen in screen map"); iter->second->UpdateScreenInfo(screenInfo); return true; } sptr screen = new Screen(screenInfo); screenMap_[screenId] = screen; return true; } } // namespace OHOS::Rosen