From c6867985dbc5cb9f1006ebae82e9ed5af1fe99e7 Mon Sep 17 00:00:00 2001 From: wlj Date: Tue, 21 Jun 2022 16:28:34 +0800 Subject: [PATCH] window visibility update Signed-off-by: wlj Change-Id: I37cbcd052ee23a845ee8d70c116a733fedf8d040 --- .../window_visibility_info_test.cpp | 45 +++++++++- wmserver/include/window_manager_service.h | 4 + wmserver/include/window_node.h | 2 +- wmserver/include/window_node_container.h | 2 - wmserver/include/window_root.h | 7 ++ wmserver/src/window_controller.cpp | 1 + wmserver/src/window_dumper.cpp | 2 + wmserver/src/window_manager_service.cpp | 47 +++++++++- wmserver/src/window_node_container.cpp | 58 ------------ wmserver/src/window_root.cpp | 89 +++++++++++++++++++ 10 files changed, 194 insertions(+), 63 deletions(-) diff --git a/wm/test/systemtest/window_visibility_info_test.cpp b/wm/test/systemtest/window_visibility_info_test.cpp index 0cc7787d..085583c8 100644 --- a/wm/test/systemtest/window_visibility_info_test.cpp +++ b/wm/test/systemtest/window_visibility_info_test.cpp @@ -36,7 +36,7 @@ namespace { } using utils = WindowTestUtils; -constexpr int WAIT_ASYNC_MS_TIME_OUT = 1500; // 1500ms +constexpr int WAIT_ASYNC_MS_TIME_OUT = 2000; // 2000ms #define CHECK_DISPLAY_POWER_STATE_RETURN() \ do { \ @@ -327,6 +327,49 @@ end: window2->Destroy(); subWindow2->Destroy(); } + +/** +* @tc.name: WindowVisibilityInfoTest04 +* @tc.desc: add two main window and sub windows and test callback +* @tc.type: FUNC +*/ +HWTEST_F(WindowVisibilityInfoTest, WindowVisibilityInfoTest04, Function | MediumTest | Level1) +{ + floatAppInfo_.name = "window1"; + floatAppInfo_.rect = {0, 0, 300, 600}; + sptr window1 = utils::CreateTestWindow(floatAppInfo_); + + floatAppInfo_.name = "window2"; + floatAppInfo_.rect = {0, 0, 300, 300}; + sptr window2 = utils::CreateTestWindow(floatAppInfo_); + + floatAppInfo_.name = "window3"; + floatAppInfo_.rect = {0, 300, 300, 300}; + sptr window3 = utils::CreateTestWindow(floatAppInfo_); + + ASSERT_EQ(WMError::WM_OK, window1->Show()); + WaitForCallback(); + CHECK_DISPLAY_POWER_STATE_RETURN(); + ASSERT_EQ(1, visibilityChangedListener_->windowVisibilityInfos_.size()); + ResetCallbackCalledFLag(); + + ASSERT_EQ(WMError::WM_OK, window2->Show()); + WaitForCallback(); + CHECK_DISPLAY_POWER_STATE_RETURN(); + ASSERT_EQ(1, visibilityChangedListener_->windowVisibilityInfos_.size()); + ResetCallbackCalledFLag(); + + ASSERT_EQ(WMError::WM_OK, window3->Show()); + WaitForCallback(); + CHECK_DISPLAY_POWER_STATE_RETURN(); + ASSERT_EQ(2, visibilityChangedListener_->windowVisibilityInfos_.size()); + ResetCallbackCalledFLag(); + +end: + window1->Destroy(); + window2->Destroy(); + window3->Destroy(); +} } } // namespace Rosen } // namespace OHOS diff --git a/wmserver/include/window_manager_service.h b/wmserver/include/window_manager_service.h index b92d1c75..e4b2c19f 100644 --- a/wmserver/include/window_manager_service.h +++ b/wmserver/include/window_manager_service.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "display_change_listener.h" #include "drag_controller.h" #include "freeze_controller.h" @@ -111,6 +112,8 @@ private: bool Init(); void RegisterSnapshotHandler(); void RegisterWindowManagerServiceHandler(); + void RegisterWindowVisibilityChangeCallback(); + void WindowVisibilityChangeCallback(std::shared_ptr occlusionData); void OnWindowEvent(Event event, const sptr& remoteObject); void NotifyDisplayStateChange(DisplayId defaultDisplayId, sptr displayInfo, const std::map>& displayInfoMap, DisplayStateChangeType type); @@ -131,6 +134,7 @@ private: SystemConfig systemConfig_; ModeChangeHotZonesConfig hotZonesConfig_ { false, 0, 0, 0 }; std::unique_ptr wmsTaskLooper_; + RSInterfaces& rsInterface_; bool startingOpen_ = true; }; } diff --git a/wmserver/include/window_node.h b/wmserver/include/window_node.h index 194cbd3c..cd87be66 100644 --- a/wmserver/include/window_node.h +++ b/wmserver/include/window_node.h @@ -115,7 +115,7 @@ public: int32_t priority_ { 0 }; bool requestedVisibility_ { false }; bool currentVisibility_ { false }; - bool isCovered_ { true }; // initial value true to ensure notification when this window is shown + bool isVisible_ { false }; bool isAppCrash_ { false }; bool isPlayAnimationShow_ { false }; bool isPlayAnimationHide_ { false }; diff --git a/wmserver/include/window_node_container.h b/wmserver/include/window_node_container.h index 1afda27d..1f623c9f 100644 --- a/wmserver/include/window_node_container.h +++ b/wmserver/include/window_node_container.h @@ -131,8 +131,6 @@ private: bool TraverseFromTopToBottom(sptr node, const WindowNodeOperationFunc& func) const; bool TraverseFromBottomToTop(sptr node, const WindowNodeOperationFunc& func) const; void RecoverScreenDefaultOrientationIfNeed(DisplayId displayId); - // cannot determine in case of a window covered by union of several windows or with transparent value - void UpdateWindowVisibilityInfos(std::vector>& infos); void RaiseOrderedWindowToTop(std::vector>& orderedNodes, std::vector>& windowNodes); static bool ReadIsWindowAnimationEnabledProperty(); diff --git a/wmserver/include/window_root.h b/wmserver/include/window_root.h index 243d9d39..9b08d698 100644 --- a/wmserver/include/window_root.h +++ b/wmserver/include/window_root.h @@ -17,6 +17,7 @@ #include #include +#include #include "agent_death_recipient.h" #include "display_manager_service_inner.h" @@ -51,6 +52,8 @@ public: bool IsForbidDockSliceMove(DisplayId displayId) const; bool IsDockSliceInExitSplitModeArea(DisplayId displayId) const; void ExitSplitMode(DisplayId displayId); + void NotifyWindowVisibilityChange(std::shared_ptr occlusionData); + void AddSurfaceNodeIdWindowNodePair(uint64_t surfaceNodeId, sptr node); WMError RequestFocus(uint32_t windowId); WMError RequestActiveWindow(uint32_t windowId); @@ -114,8 +117,12 @@ private: void MoveNotShowingWindowToDefaultDisplay(DisplayId defaultDisplayId, DisplayId displayId); WMError PostProcessAddWindowNode(sptr& node, sptr& parentNode, sptr& container); + std::vector> GetWindowVisibilityChangeInfo( + std::shared_ptr occlusionData); std::map> windowNodeMap_; std::map, uint32_t> windowIdMap_; + std::map> surfaceIdWindowNodeMap_; + std::shared_ptr lastOcclusionData_ = std::make_shared(); std::map> windowNodeContainerMap_; std::map> displayIdMap_; diff --git a/wmserver/src/window_controller.cpp b/wmserver/src/window_controller.cpp index 627dd869..df2816a2 100644 --- a/wmserver/src/window_controller.cpp +++ b/wmserver/src/window_controller.cpp @@ -170,6 +170,7 @@ WMError WindowController::CreateWindow(sptr& window, sptrGetWindowType()) && node->startingWindowShown_) { StartingWindow::HandleClientWindowCreate(node, window, windowId, surfaceNode, property, pid, uid); windowRoot_->AddDeathRecipient(node); + windowRoot_->AddSurfaceNodeIdWindowNodePair(surfaceNode->GetId(), node); return WMError::WM_OK; } windowId = GenWindowId(); diff --git a/wmserver/src/window_dumper.cpp b/wmserver/src/window_dumper.cpp index eb11421d..134ee8f6 100644 --- a/wmserver/src/window_dumper.cpp +++ b/wmserver/src/window_dumper.cpp @@ -166,6 +166,7 @@ WMError WindowDumper::DumpSpecifiedWindowInfo(uint32_t windowId, const std::vect } Rect rect = node->GetWindowRect(); std::string isShown_ = node->startingWindowShown_ ? "true" : "false"; + std::string isVisible = node->isVisible_ ? "true" : "false"; std::ostringstream oss; oss << "WindowName: " << node->GetWindowName() << std::endl; oss << "DisplayId: " << node->GetDisplayId() << std::endl; @@ -176,6 +177,7 @@ WMError WindowDumper::DumpSpecifiedWindowInfo(uint32_t windowId, const std::vect oss << "Flag: " << node->GetWindowFlags() << std::endl; oss << "Orientation: " << static_cast(node->GetRequestedOrientation()) << std::endl; oss << "IsStartingWindow: " << isShown_ << std::endl; + oss << "IsVisible: " << isVisible << std::endl; oss << "WindowRect: " << "[ " << rect.posX_ << ", " << rect.posY_ << ", " << rect.width_ << ", " << rect.height_ << " ]" << std::endl; diff --git a/wmserver/src/window_manager_service.cpp b/wmserver/src/window_manager_service.cpp index f36feb3b..9afbb2e7 100644 --- a/wmserver/src/window_manager_service.cpp +++ b/wmserver/src/window_manager_service.cpp @@ -46,7 +46,8 @@ WM_IMPLEMENT_SINGLE_INSTANCE(WindowManagerService) const bool REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(&SingletonContainer::Get()); -WindowManagerService::WindowManagerService() : SystemAbility(WINDOW_MANAGER_SERVICE_ID, true) +WindowManagerService::WindowManagerService() : SystemAbility(WINDOW_MANAGER_SERVICE_ID, true), + rsInterface_(RSInterfaces::GetInstance()) { windowRoot_ = new WindowRoot( std::bind(&WindowManagerService::OnWindowEvent, this, std::placeholders::_1, std::placeholders::_2)); @@ -71,9 +72,53 @@ void WindowManagerService::OnStart() DisplayManagerServiceInner::GetInstance().RegisterDisplayChangeListener(listener); RegisterSnapshotHandler(); RegisterWindowManagerServiceHandler(); + RegisterWindowVisibilityChangeCallback(); wmsTaskLooper_->Start(); } + +void WindowManagerService::WindowVisibilityChangeCallback(std::shared_ptr occlusionData) +{ + WLOGFD("NotifyWindowVisibilityChange: enter"); + std::weak_ptr weak(occlusionData); + return wmsTaskLooper_->ScheduleTask([this, weak]() { + auto weakOcclusionData = weak.lock(); + if (weakOcclusionData == nullptr) { + WLOGFE("weak occlusionData is nullptr"); + return; + } + windowRoot_->NotifyWindowVisibilityChange(weakOcclusionData); + }).wait(); +} + +void WindowManagerService::RegisterWindowVisibilityChangeCallback() +{ + auto windowVisibilityChangeCb = std::bind(&WindowManagerService::WindowVisibilityChangeCallback, this, + std::placeholders::_1); + if (rsInterface_.RegisterOcclusionChangeCallback(windowVisibilityChangeCb) != WM_OK) { + WLOGFW("WindowManagerService::RegisterWindowVisibilityChangeCallback failed, create async thread!"); + auto fun = [this, windowVisibilityChangeCb]() { + WLOGFI("WindowManagerService::RegisterWindowVisibilityChangeCallback async thread enter!"); + int counter = 0; + while (rsInterface_.RegisterOcclusionChangeCallback(windowVisibilityChangeCb) != WM_OK) { + usleep(10000); // 10000us equals to 10ms + counter++; + if (counter >= 2000) { // wait for 2000 * 10ms = 20s + WLOGFE("WindowManagerService::RegisterWindowVisibilityChangeCallback timeout!"); + return; + } + } + WLOGFI("WindowManagerService::RegisterWindowVisibilityChangeCallback async thread register handler" + " successfully!"); + }; + std::thread thread(fun); + thread.detach(); + WLOGFI("WindowManagerService::RegisterWindowVisibilityChangeCallback async thread has been detached!"); + } else { + WLOGFI("WindowManagerService::RegisterWindowVisibilityChangeCallback OnStart succeed!"); + } +} + void WindowManagerService::RegisterSnapshotHandler() { if (snapshotController_ == nullptr) { diff --git a/wmserver/src/window_node_container.cpp b/wmserver/src/window_node_container.cpp index fdc02692..352a9fdc 100644 --- a/wmserver/src/window_node_container.cpp +++ b/wmserver/src/window_node_container.cpp @@ -179,8 +179,6 @@ WMError WindowNodeContainer::AddWindowNode(sptr& node, sptrAddWindowNode(node); NotifyIfAvoidAreaChanged(node, AvoidControlType::AVOID_NODE_ADD); - std::vector> infos; - UpdateWindowVisibilityInfos(infos); DumpScreenWindowTree(); NotifyAccessibilityWindowInfo(node, WindowUpdateType::WINDOW_UPDATE_ADDED); WLOGFI("AddWindowNode windowId: %{public}u end", node->GetWindowId()); @@ -268,17 +266,6 @@ WMError WindowNodeContainer::RemoveWindowNode(sptr& node) node->requestedVisibility_ = false; node->currentVisibility_ = false; - node->isCovered_ = true; - std::vector> infos = {new WindowVisibilityInfo(node->GetWindowId(), - node->GetCallingPid(), node->GetCallingUid(), false, node->GetWindowType())}; - for (auto& child : node->children_) { - if (child->currentVisibility_) { - child->currentVisibility_ = false; - child->isCovered_ = true; - infos.emplace_back(new WindowVisibilityInfo(child->GetWindowId(), child->GetCallingPid(), - child->GetCallingUid(), false, child->GetWindowType())); - } - } // Remove node from RSTree for (auto& displayId : node->GetShowingDisplays()) { UpdateRSTree(node, displayId, false, node->isPlayAnimationHide_); @@ -297,7 +284,6 @@ WMError WindowNodeContainer::RemoveWindowNode(sptr& node) NotifyDockWindowStateChanged(node, true); } NotifyIfAvoidAreaChanged(node, AvoidControlType::AVOID_NODE_REMOVE); - UpdateWindowVisibilityInfos(infos); DumpScreenWindowTree(); NotifyAccessibilityWindowInfo(node, WindowUpdateType::WINDOW_UPDATE_REMOVED); RecoverScreenDefaultOrientationIfNeed(node->GetDisplayId()); @@ -1720,50 +1706,6 @@ bool WindowNodeContainer::TraverseFromBottomToTop(sptr node, const W return false; } -void WindowNodeContainer::UpdateWindowVisibilityInfos(std::vector>& infos) -{ - // clear vector cache completely, swap with empty vector - auto emptyVector = std::vector(); - currentCoveredArea_.swap(emptyVector); - WindowNodeOperationFunc func = [this, &infos](sptr node) { - if (node == nullptr) { - return false; - } - Rect layoutRect = node->GetWindowRect(); - const Rect& displayRect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId()); - int32_t nodeX = std::max(0, layoutRect.posX_); - int32_t nodeY = std::max(0, layoutRect.posY_); - int32_t nodeXEnd = std::min(displayRect.posX_ + static_cast(displayRect.width_), - layoutRect.posX_ + static_cast(layoutRect.width_)); - int32_t nodeYEnd = std::min(displayRect.posY_ + static_cast(displayRect.height_), - layoutRect.posY_ + static_cast(layoutRect.height_)); - - Rect rectInDisplay = {nodeX, nodeY, - static_cast(nodeXEnd - nodeX), static_cast(nodeYEnd - nodeY)}; - bool isCovered = false; - for (auto& rect : currentCoveredArea_) { - if (rectInDisplay.IsInsideOf(rect)) { - isCovered = true; - WLOGD("UpdateWindowVisibilityInfos: find covered window:%{public}u", node->GetWindowId()); - break; - } - } - if (!isCovered) { - currentCoveredArea_.emplace_back(rectInDisplay); - } - if (isCovered != node->isCovered_) { - node->isCovered_ = isCovered; - infos.emplace_back(new WindowVisibilityInfo(node->GetWindowId(), node->GetCallingPid(), - node->GetCallingUid(), !isCovered, node->GetWindowType())); - WLOGD("UpdateWindowVisibilityInfos: covered status changed window:%{public}u, covered:%{public}d", - node->GetWindowId(), isCovered); - } - return false; - }; - TraverseWindowTree(func, true); - WindowManagerAgentController::GetInstance().UpdateWindowVisibilityInfo(infos); -} - float WindowNodeContainer::GetVirtualPixelRatio(DisplayId displayId) const { return layoutPolicy_->GetVirtualPixelRatio(displayId); diff --git a/wmserver/src/window_root.cpp b/wmserver/src/window_root.cpp index 4f7b1263..18fb24cc 100644 --- a/wmserver/src/window_root.cpp +++ b/wmserver/src/window_root.cpp @@ -24,6 +24,7 @@ #include "window_manager_hilog.h" #include "window_manager_service.h" #include "wm_trace.h" +#include "window_manager_agent_controller.h" namespace OHOS { namespace Rosen { @@ -181,6 +182,9 @@ WMError WindowRoot::SaveWindow(const sptr& node) WLOGFI("save windowId %{public}u", node->GetWindowId()); windowNodeMap_.insert(std::make_pair(node->GetWindowId(), node)); + if (node->surfaceNode_ != nullptr) { + surfaceIdWindowNodeMap_.insert(std::make_pair(node->surfaceNode_->GetId(), node)); + } if (node->GetWindowToken()) { AddDeathRecipient(node); } @@ -256,6 +260,69 @@ void WindowRoot::ExitSplitMode(DisplayId displayId) container->ExitSplitMode(displayId); } + +void WindowRoot::AddSurfaceNodeIdWindowNodePair(uint64_t surfaceNodeId, sptr node) +{ + surfaceIdWindowNodeMap_.insert(std::make_pair(surfaceNodeId, node)); +} + +std::vector> WindowRoot::GetWindowVisibilityChangeInfo( + std::shared_ptr occlusionData) +{ + std::vector> visibityChangeInfo; + VisibleData& currentVisibleWindow = occlusionData->GetVisibleData(); + std::sort(currentVisibleWindow.begin(), currentVisibleWindow.end()); + VisibleData& lastVisibleWindow = lastOcclusionData_->GetVisibleData(); + uint32_t i, j; + i = j = 0; + for (; i < lastVisibleWindow.size() && j < currentVisibleWindow.size();) { + if (lastVisibleWindow[i] < currentVisibleWindow[j]) { + visibityChangeInfo.push_back(std::make_pair(lastVisibleWindow[i], false)); + i++; + } else if (lastVisibleWindow[i] > currentVisibleWindow[j]) { + visibityChangeInfo.push_back(std::make_pair(currentVisibleWindow[j], true)); + j++; + } else { + i++; + j++; + } + } + for (; i < lastVisibleWindow.size(); ++i) { + visibityChangeInfo.push_back(std::make_pair(lastVisibleWindow[i], false)); + } + for (; j < currentVisibleWindow.size(); ++j) { + visibityChangeInfo.push_back(std::make_pair(currentVisibleWindow[j], true)); + } + lastOcclusionData_ = occlusionData; + return visibityChangeInfo; +} + +void WindowRoot::NotifyWindowVisibilityChange(std::shared_ptr occlusionData) +{ + std::vector> visibityChangeInfo = GetWindowVisibilityChangeInfo(occlusionData); + std::vector> windowVisibilityInfos; + for (const auto& elem : visibityChangeInfo) { + uint64_t surfaceId = elem.first; + bool isVisible = elem.second; + auto iter = surfaceIdWindowNodeMap_.find(surfaceId); + if (iter == surfaceIdWindowNodeMap_.end()) { + continue; + } + sptr node = iter->second; + if (node == nullptr) { + continue; + } + node->isVisible_ = isVisible; + windowVisibilityInfos.emplace_back(new WindowVisibilityInfo(node->GetWindowId(), node->GetCallingPid(), + node->GetCallingUid(), isVisible, node->GetWindowType())); + WLOGFD("NotifyWindowVisibilityChange: covered status changed window:%{public}u, isVisible:%{public}d", + node->GetWindowId(), isVisible); + } + if (windowVisibilityInfos.size() != 0) { + WindowManagerAgentController::GetInstance().UpdateWindowVisibilityInfo(windowVisibilityInfos); + } +} + std::vector WindowRoot::GetAvoidAreaByType(uint32_t windowId, AvoidAreaType avoidAreaType) { std::vector avoidArea; @@ -631,6 +698,28 @@ WMError WindowRoot::DestroyWindowInner(sptr& node) return WMError::WM_ERROR_DESTROYED_OBJECT; } + std::vector> windowVisibilityInfos; + node->isVisible_ = false; + windowVisibilityInfos.emplace_back(new WindowVisibilityInfo(node->GetWindowId(), node->GetCallingPid(), + node->GetCallingUid(), false, node->GetWindowType())); + WLOGFD("NotifyWindowVisibilityChange: covered status changed window:%{public}u, isVisible:%{public}d", + node->GetWindowId(), node->isVisible_); + WindowManagerAgentController::GetInstance().UpdateWindowVisibilityInfo(windowVisibilityInfos); + + auto cmpFunc = [node](const std::map>::value_type& pair) { + if (pair.second == nullptr) { + return false; + } + if (pair.second->GetWindowId() == node->GetWindowId()) { + return true; + } + return false; + }; + auto iter = std::find_if(surfaceIdWindowNodeMap_.begin(), surfaceIdWindowNodeMap_.end(), cmpFunc); + if (iter != surfaceIdWindowNodeMap_.end()) { + surfaceIdWindowNodeMap_.erase(iter); + } + sptr window = node->GetWindowToken(); if ((window != nullptr) && (window->AsObject() != nullptr)) { if (windowIdMap_.count(window->AsObject()) == 0) {