Files
windowmanager/dmserver/src/abstract_display_controller.cpp
T
l00574490 9edb93bd38 support drag cross display
Signed-off-by: l00574490 <liuqi149@huawei.com>
Change-Id: I2683659a054879d79df8607604843623a6bf882d
2022-05-13 17:33:30 +08:00

517 lines
23 KiB
C++

/*
* 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 "abstract_display_controller.h"
#include <cinttypes>
#include <surface.h>
#include "display_manager_agent_controller.h"
#include "display_manager_service.h"
#include "screen_group.h"
#include "window_manager_hilog.h"
#include "wm_trace.h"
namespace OHOS::Rosen {
namespace {
constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "AbstractDisplayController"};
}
AbstractDisplayController::AbstractDisplayController(std::recursive_mutex& mutex, DisplayStateChangeListener listener)
: mutex_(mutex), rsInterface_(RSInterfaces::GetInstance()), displayStateChangeListener_(listener)
{
}
AbstractDisplayController::~AbstractDisplayController()
{
abstractScreenController_ = nullptr;
}
void AbstractDisplayController::Init(sptr<AbstractScreenController> abstractScreenController)
{
WLOGFD("display controller init");
displayCount_ = 0;
abstractScreenController_ = abstractScreenController;
abstractScreenCallback_ = new(std::nothrow) AbstractScreenController::AbstractScreenCallback();
if (abstractScreenCallback_ == nullptr) {
WLOGFE("abstractScreenCallback init failed");
return;
}
abstractScreenCallback_->onConnect_
= std::bind(&AbstractDisplayController::OnAbstractScreenConnect, this, std::placeholders::_1);
abstractScreenCallback_->onDisconnect_
= std::bind(&AbstractDisplayController::OnAbstractScreenDisconnect, this, std::placeholders::_1);
abstractScreenCallback_->onChange_
= std::bind(&AbstractDisplayController::OnAbstractScreenChange, this, std::placeholders::_1,
std::placeholders::_2);
abstractScreenController_->ScreenConnectionInDisplayInit(abstractScreenCallback_);
abstractScreenController->RegisterAbstractScreenCallback(abstractScreenCallback_);
}
ScreenId AbstractDisplayController::GetDefaultScreenId()
{
return rsInterface_.GetDefaultScreenId();
}
RSScreenModeInfo AbstractDisplayController::GetScreenActiveMode(ScreenId id)
{
return rsInterface_.GetScreenActiveMode(id);
}
sptr<AbstractDisplay> AbstractDisplayController::GetAbstractDisplay(DisplayId displayId) const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
auto iter = abstractDisplayMap_.find(displayId);
if (iter == abstractDisplayMap_.end()) {
WLOGFE("Failed to get AbstractDisplay %{public}" PRIu64", return nullptr!", displayId);
return nullptr;
}
return iter->second;
}
sptr<AbstractDisplay> AbstractDisplayController::GetAbstractDisplayByScreen(ScreenId screenId) const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
for (auto iter : abstractDisplayMap_) {
sptr<AbstractDisplay> display = iter.second;
if (display->GetAbstractScreenId() == screenId) {
return display;
}
}
WLOGFE("fail to get AbstractDisplay %{public}" PRIu64"", screenId);
return nullptr;
}
std::vector<DisplayId> AbstractDisplayController::GetAllDisplayIds() const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
std::vector<DisplayId> res;
for (auto iter = abstractDisplayMap_.begin(); iter != abstractDisplayMap_.end(); ++iter) {
res.push_back(iter->first);
}
return res;
}
std::shared_ptr<Media::PixelMap> AbstractDisplayController::GetScreenSnapshot(DisplayId displayId)
{
sptr<AbstractDisplay> abstractDisplay = GetAbstractDisplay(displayId);
if (abstractDisplay == nullptr) {
WLOGFE("GetScreenSnapshot: GetAbstarctDisplay failed");
return nullptr;
}
ScreenId dmsScreenId = abstractDisplay->GetAbstractScreenId();
std::shared_ptr<RSDisplayNode> displayNode = abstractScreenController_->GetRSDisplayNodeByScreenId(dmsScreenId);
std::lock_guard<std::recursive_mutex> lock(mutex_);
std::shared_ptr<ScreenshotCallback> callback = std::make_shared<ScreenshotCallback>();
rsInterface_.TakeSurfaceCapture(displayNode, callback);
std::shared_ptr<Media::PixelMap> screenshot = callback->GetResult(2000); // wait for 2000ms
if (screenshot == nullptr) {
WLOGFE("Failed to get pixelmap from RS, return nullptr!");
}
return screenshot;
}
void AbstractDisplayController::OnAbstractScreenConnect(sptr<AbstractScreen> absScreen)
{
if (absScreen == nullptr) {
WLOGFE("absScreen is null");
return;
}
WLOGI("connect new screen. id:%{public}" PRIu64"", absScreen->dmsId_);
std::lock_guard<std::recursive_mutex> lock(mutex_);
sptr<AbstractScreenGroup> group = absScreen->GetGroup();
if (group == nullptr) {
WLOGE("the group information of the screen is wrong");
return;
}
if (group->combination_ == ScreenCombination::SCREEN_ALONE || group->GetChildCount() == 1) {
BindAloneScreenLocked(absScreen);
} else if (group->combination_ == ScreenCombination::SCREEN_MIRROR) {
WLOGI("OnAbstractScreenConnect, ScreenCombination::SCREEN_MIRROR, AddScreenToMirrorLocked");
AddScreenToMirrorLocked(absScreen);
} else if (group->combination_ == ScreenCombination::SCREEN_EXPAND) {
WLOGI("OnAbstractScreenConnect, ScreenCombination::SCREEN_EXPAND, AddScreenToExpandLocked");
AddScreenToExpandLocked(absScreen);
} else {
WLOGE("support in future. combination:%{public}u", group->combination_);
}
}
void AbstractDisplayController::OnAbstractScreenDisconnect(sptr<AbstractScreen> absScreen)
{
if (absScreen == nullptr) {
WLOGE("the information of the screen is wrong");
return;
}
WLOGI("disconnect screen. id:%{public}" PRIu64"", absScreen->dmsId_);
sptr<AbstractScreenGroup> screenGroup;
DisplayId absDisplayId = DISPLAY_ID_INVALID;
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
screenGroup = absScreen->GetGroup();
if (screenGroup == nullptr) {
WLOGE("the group information of the screen is wrong");
return;
}
if (screenGroup->combination_ == ScreenCombination::SCREEN_ALONE
|| screenGroup->combination_ == ScreenCombination::SCREEN_MIRROR) {
absDisplayId = ProcessNormalScreenDisconnected(absScreen, screenGroup);
} else if (screenGroup->combination_ == ScreenCombination::SCREEN_EXPAND) {
absDisplayId = ProcessExpandScreenDisconnected(absScreen, screenGroup);
} else {
WLOGE("support in future. combination:%{public}u", screenGroup->combination_);
}
}
if (absDisplayId == DISPLAY_ID_INVALID) {
WLOGE("the displayId of the disconnected expand screen was not found");
return;
}
if (screenGroup->combination_ == ScreenCombination::SCREEN_ALONE
|| screenGroup->combination_ == ScreenCombination::SCREEN_MIRROR) {
if (screenGroup->GetChildCount() == 0) {
abstractDisplayMap_.erase(absDisplayId);
DisplayManagerAgentController::GetInstance().OnDisplayDestroy(absDisplayId);
}
} else if (screenGroup->combination_ == ScreenCombination::SCREEN_EXPAND) {
displayStateChangeListener_(absDisplayId, DisplayStateChangeType::DESTROY);
DisplayManagerAgentController::GetInstance().OnDisplayDestroy(absDisplayId);
abstractDisplayMap_.erase(absDisplayId);
} else {
WLOGE("support in future. combination:%{public}u", screenGroup->combination_);
}
}
DisplayId AbstractDisplayController::ProcessNormalScreenDisconnected(
sptr<AbstractScreen> absScreen, sptr<AbstractScreenGroup> screenGroup)
{
WLOGI("normal screen disconnect");
if (absScreen == nullptr || screenGroup == nullptr) {
WLOGFE("Invalid params as nullptr.");
return DISPLAY_ID_INVALID;
}
ScreenId defaultScreenId = abstractScreenController_->GetDefaultAbstractScreenId();
sptr<AbstractScreen> defaultScreen = abstractScreenController_->GetAbstractScreen(defaultScreenId);
for (auto iter = abstractDisplayMap_.begin(); iter != abstractDisplayMap_.end(); iter++) {
DisplayId displayId = iter->first;
sptr<AbstractDisplay> abstractDisplay = iter->second;
if (abstractDisplay->GetAbstractScreenId() == absScreen->dmsId_) {
WLOGI("normal screen disconnect, displayId: %{public}" PRIu64", screenId: %{public}" PRIu64"",
displayId, abstractDisplay->GetAbstractScreenId());
abstractDisplay->BindAbstractScreen(defaultScreen);
return displayId;
}
}
return DISPLAY_ID_INVALID;
}
DisplayId AbstractDisplayController::ProcessExpandScreenDisconnected(
sptr<AbstractScreen> absScreen, sptr<AbstractScreenGroup> screenGroup)
{
WLOGI("expand screen disconnect");
if (absScreen == nullptr || screenGroup == nullptr) {
WLOGFE("Invalid params as nullptr.");
return DISPLAY_ID_INVALID;
}
DisplayId displayId = DISPLAY_ID_INVALID;
for (auto iter = abstractDisplayMap_.begin(); iter != abstractDisplayMap_.end(); iter++) {
sptr<AbstractDisplay> abstractDisplay = iter->second;
if (abstractDisplay->GetAbstractScreenId() == absScreen->dmsId_) {
WLOGI("expand screen disconnect, displayId: %{public}" PRIu64", screenId: %{public}" PRIu64"",
displayId, abstractDisplay->GetAbstractScreenId());
displayId = iter->first;
} else {
abstractDisplay->SetOffset(0, 0);
auto screenId = abstractDisplay->GetAbstractScreenId();
abstractScreenController_->GetRSDisplayNodeByScreenId(screenId)->SetDisplayOffset(0, 0);
}
}
return displayId;
}
void AbstractDisplayController::OnAbstractScreenChange(sptr<AbstractScreen> absScreen, DisplayChangeEvent event)
{
if (absScreen == nullptr) {
WLOGE("OnAbstractScreenChanged::the information of the screen is wrong");
return;
}
WLOGI("screen changes. id:%{public}" PRIu64"", absScreen->dmsId_);
if (event == DisplayChangeEvent::UPDATE_ORIENTATION) {
ProcessDisplayUpdateOrientation(absScreen);
} else if (event == DisplayChangeEvent::DISPLAY_SIZE_CHANGED) {
ProcessDisplaySizeChange(absScreen);
} else if (event == DisplayChangeEvent::DISPLAY_VIRTUAL_PIXEL_RATIO_CHANGED) {
ProcessVirtualPixelRatioChange(absScreen);
} else {
WLOGE("unknown screen change event. id:%{public}" PRIu64" event %{public}u", absScreen->dmsId_, event);
}
}
void AbstractDisplayController::ProcessDisplayUpdateOrientation(sptr<AbstractScreen> absScreen)
{
sptr<AbstractDisplay> abstractDisplay = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
auto iter = abstractDisplayMap_.begin();
for (; iter != abstractDisplayMap_.end(); iter++) {
abstractDisplay = iter->second;
if (abstractDisplay->GetAbstractScreenId() == absScreen->dmsId_) {
WLOGFD("find abstract display of the screen. display %{public}" PRIu64", screen %{public}" PRIu64"",
abstractDisplay->GetId(), absScreen->dmsId_);
break;
}
}
sptr<AbstractScreenGroup> group = absScreen->GetGroup();
if (group == nullptr) {
WLOGFE("cannot get screen group");
return;
}
if (iter == abstractDisplayMap_.end()) {
if (group->combination_ == ScreenCombination::SCREEN_ALONE
|| group->combination_ == ScreenCombination::SCREEN_EXPAND) {
WLOGFE("cannot find abstract display of the screen %{public}" PRIu64"", absScreen->dmsId_);
return;
} else if (group->combination_ == ScreenCombination::SCREEN_MIRROR) {
// If the screen cannot be found in 'abstractDisplayMap_', it means that the screen is the secondary
WLOGFI("It's the secondary screen of the mirrored.");
return;
} else {
WLOGFE("Unknown combination");
return;
}
}
}
abstractDisplay->SetOrientation(absScreen->orientation_);
if (abstractDisplay->RequestRotation(absScreen->rotation_)) {
// Notify rotation event to WMS
displayStateChangeListener_(abstractDisplay->GetId(), DisplayStateChangeType::UPDATE_ROTATION);
}
// Notify orientation event to DisplayManager
sptr<DisplayInfo> displayInfo = abstractDisplay->ConvertToDisplayInfo();
DisplayManagerAgentController::GetInstance().OnDisplayChange(displayInfo,
DisplayChangeEvent::UPDATE_ORIENTATION);
}
void AbstractDisplayController::ProcessDisplaySizeChange(sptr<AbstractScreen> absScreen)
{
WM_SCOPED_TRACE("dms:ProcessDisplaySizeChange(%" PRIu64")", absScreen->dmsId_);
sptr<SupportedScreenModes> info = absScreen->GetActiveScreenMode();
if (info == nullptr) {
WLOGE("cannot get active screen info.");
return;
}
std::map<DisplayId, sptr<AbstractDisplay>> matchedDisplays;
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
for (auto iter = abstractDisplayMap_.begin(); iter != abstractDisplayMap_.end(); ++iter) {
sptr<AbstractDisplay> absDisplay = iter->second;
if (absDisplay == nullptr || absDisplay->GetAbstractScreenId() != absScreen->dmsId_) {
continue;
}
if (UpdateDisplaySize(absDisplay, info)) {
matchedDisplays.insert(std::make_pair(iter->first, iter->second));
}
}
}
WLOGFI("Size of matchedDisplays %{public}zu", matchedDisplays.size());
for (auto iter = matchedDisplays.begin(); iter != matchedDisplays.end(); ++iter) {
WLOGFI("Notify display size change. Id %{public}" PRIu64"", iter->first);
displayStateChangeListener_(iter->first, DisplayStateChangeType::SIZE_CHANGE);
DisplayManagerAgentController::GetInstance().OnDisplayChange(
iter->second->ConvertToDisplayInfo(), DisplayChangeEvent::DISPLAY_SIZE_CHANGED);
}
}
bool AbstractDisplayController::UpdateDisplaySize(sptr<AbstractDisplay> absDisplay, sptr<SupportedScreenModes> info)
{
if (absDisplay == nullptr || info == nullptr) {
WLOGFE("invalid params.");
return false;
}
if (info->height_ == static_cast<uint32_t>(absDisplay->GetHeight()) &&
info->width_ == static_cast<uint32_t>(absDisplay->GetWidth())) {
WLOGFI("keep display size. display:%{public}" PRIu64"", absDisplay->GetId());
return false;
}
absDisplay->SetHeight(info->height_);
absDisplay->SetWidth(info->width_);
WLOGFI("Reset H&W. id %{public}" PRIu64", size: %{public}d %{public}d",
absDisplay->GetId(), absDisplay->GetWidth(), absDisplay->GetHeight());
return true;
}
void AbstractDisplayController::ProcessVirtualPixelRatioChange(sptr<AbstractScreen> absScreen)
{
sptr<AbstractDisplay> abstractDisplay = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
auto iter = abstractDisplayMap_.begin();
for (; iter != abstractDisplayMap_.end(); iter++) {
abstractDisplay = iter->second;
if (abstractDisplay->GetAbstractScreenId() == absScreen->dmsId_) {
WLOGFD("find abstract display of the screen. display %{public}" PRIu64", screen %{public}" PRIu64"",
abstractDisplay->GetId(), absScreen->dmsId_);
break;
}
}
}
if (abstractDisplay == nullptr) {
WLOGE("Failed to find abstract display of the screen.");
return;
}
abstractDisplay->SetVirtualPixelRatio(absScreen->virtualPixelRatio_);
// Notify virtual pixel ratio change event to WMS
displayStateChangeListener_(abstractDisplay->GetId(), DisplayStateChangeType::VIRTUAL_PIXEL_RATIO_CHANGE);
// Notify virtual pixel ratio change event to DisplayManager
sptr<DisplayInfo> displayInfo = abstractDisplay->ConvertToDisplayInfo();
DisplayManagerAgentController::GetInstance().OnDisplayChange(displayInfo,
DisplayChangeEvent::DISPLAY_VIRTUAL_PIXEL_RATIO_CHANGED);
}
void AbstractDisplayController::BindAloneScreenLocked(sptr<AbstractScreen> realAbsScreen)
{
if (realAbsScreen == nullptr) {
WLOGE("BindAloneScreenLocked failed, realAbsScreen is nullptr");
return;
}
ScreenId defaultScreenId = abstractScreenController_->GetDefaultAbstractScreenId();
if (defaultScreenId != SCREEN_ID_INVALID) {
if (defaultScreenId != realAbsScreen->dmsId_) {
WLOGE("The first real screen should be default for Phone. %{public}" PRIu64"", realAbsScreen->dmsId_);
return;
}
sptr<SupportedScreenModes> info = realAbsScreen->GetActiveScreenMode();
if (info == nullptr) {
WLOGE("bind alone screen error, cannot get info.");
return;
}
if (dummyDisplay_ == nullptr) {
sptr<AbstractDisplay> display = new(std::nothrow) AbstractDisplay(displayCount_.fetch_add(1),
realAbsScreen->dmsId_, info->width_, info->height_, info->refreshRate_);
if (display == nullptr) {
WLOGFE("create display failed");
return;
}
abstractDisplayMap_.insert((std::make_pair(display->GetId(), display)));
WLOGI("create display for new screen. screen:%{public}" PRIu64", display:%{public}" PRIu64"",
realAbsScreen->dmsId_, display->GetId());
DisplayManagerAgentController::GetInstance().OnDisplayCreate(display->ConvertToDisplayInfo());
displayStateChangeListener_(display->GetId(), DisplayStateChangeType::CREATE);
} else {
WLOGI("bind display for new screen. screen:%{public}" PRIu64", display:%{public}" PRIu64"",
realAbsScreen->dmsId_, dummyDisplay_->GetId());
bool updateFlag = dummyDisplay_->GetHeight() == info->height_ && dummyDisplay_->GetWidth() == info->width_;
dummyDisplay_->BindAbstractScreen(abstractScreenController_->GetAbstractScreen(realAbsScreen->dmsId_));
if (updateFlag) {
DisplayManagerAgentController::GetInstance().OnDisplayCreate(dummyDisplay_->ConvertToDisplayInfo());
}
dummyDisplay_ = nullptr;
}
} else {
WLOGE("The first real screen should be default screen for Phone. %{public}" PRIu64"", realAbsScreen->dmsId_);
}
}
void AbstractDisplayController::AddScreenToMirrorLocked(sptr<AbstractScreen> absScreen)
{
WLOGI("bind display to mirror. screen:%{public}" PRIu64"", absScreen->dmsId_);
}
void AbstractDisplayController::AddScreenToExpandLocked(sptr<AbstractScreen> absScreen)
{
if (absScreen == nullptr) {
WLOGE("AddScreenToExpandLocked failed, absScreen is nullptr");
return;
}
for (auto iter = abstractDisplayMap_.begin(); iter != abstractDisplayMap_.end(); iter++) {
sptr<AbstractDisplay> abstractDisplay = iter->second;
if (abstractDisplay->GetAbstractScreenId() == absScreen->dmsId_) {
WLOGE("error, screenId: %{public}" PRIu64" already has corresponding display",
absScreen->dmsId_);
return;
}
}
WLOGI("bind display to expand. screen:%{public}" PRIu64"", absScreen->dmsId_);
sptr<SupportedScreenModes> info;
if (absScreen->type_ == ScreenType::VIRTUAL) {
WLOGI("screen type is virtual, use default screen info");
ScreenId defaultScreenId = abstractScreenController_->GetDefaultAbstractScreenId();
sptr<AbstractScreen> defaultScreen = abstractScreenController_->GetAbstractScreen(defaultScreenId);
if (defaultScreen == nullptr) {
WLOGE("bind display error, cannot get defaultScreen.");
return;
}
info = defaultScreen->GetActiveScreenMode();
} else {
WLOGI("screen type is not virtual, get this screen info");
info = absScreen->GetActiveScreenMode();
}
if (info == nullptr) {
WLOGE("bind display error, cannot get info.");
return;
}
sptr<AbstractDisplay> display = new AbstractDisplay(displayCount_.fetch_add(1),
absScreen->dmsId_, info->width_, info->height_, info->refreshRate_);
Point point = abstractScreenController_->GetAbstractScreenGroup(absScreen->groupDmsId_)->
GetChildPosition(absScreen->dmsId_);
display->SetOffset(point.posX_, point.posY_);
abstractDisplayMap_.insert((std::make_pair(display->GetId(), display)));
WLOGI("create display for new screen. screen:%{public}" PRIu64", display:%{public}" PRIu64"",
absScreen->dmsId_, display->GetId());
DisplayManagerAgentController::GetInstance().OnDisplayCreate(display->ConvertToDisplayInfo());
displayStateChangeListener_(display->GetId(), DisplayStateChangeType::CREATE);
}
void AbstractDisplayController::SetFreeze(std::vector<DisplayId> displayIds, bool toFreeze)
{
WM_SCOPED_TRACE("dms:SetAllFreeze");
DisplayStateChangeType type = toFreeze ? DisplayStateChangeType::FREEZE : DisplayStateChangeType::UNFREEZE;
DisplayChangeEvent event
= toFreeze ? DisplayChangeEvent::DISPLAY_FREEZED : DisplayChangeEvent::DISPLAY_UNFREEZED;
for (DisplayId displayId : displayIds) {
sptr<AbstractDisplay> abstractDisplay;
WM_SCOPED_TRACE("dms:SetFreeze(%" PRIu64")", displayId);
{
WLOGI("setfreeze display %{public}" PRIu64"", displayId);
std::lock_guard<std::recursive_mutex> lock(mutex_);
auto iter = abstractDisplayMap_.find(displayId);
if (iter == abstractDisplayMap_.end()) {
WLOGE("setfreeze fail, cannot get display %{public}" PRIu64"", displayId);
continue;
}
abstractDisplay = iter->second;
FreezeFlag curFlag = abstractDisplay->GetFreezeFlag();
if ((toFreeze && (curFlag == FreezeFlag::FREEZING))
|| (!toFreeze && (curFlag == FreezeFlag::UNFREEZING))) {
WLOGE("setfreeze fail, display %{public}" PRIu64" freezeflag is %{public}u",
displayId, curFlag);
continue;
}
FreezeFlag flag = toFreeze ? FreezeFlag::FREEZING : FreezeFlag::UNFREEZING;
abstractDisplay->SetFreezeFlag(flag);
}
// Notify freeze event to WMS
displayStateChangeListener_(displayId, type);
// Notify freeze event to DisplayManager
sptr<DisplayInfo> displayInfo = abstractDisplay->ConvertToDisplayInfo();
DisplayManagerAgentController::GetInstance().OnDisplayChange(displayInfo, event);
}
}
} // namespace OHOS::Rosen