diff --git a/wmserver/BUILD.gn b/wmserver/BUILD.gn index e08dec27..43ef3d51 100644 --- a/wmserver/BUILD.gn +++ b/wmserver/BUILD.gn @@ -67,6 +67,7 @@ ohos_shared_library("libwms") { "src/window_manager_stub.cpp", "src/window_node.cpp", "src/window_node_container.cpp", + "src/window_pair.cpp", "src/window_root.cpp", "src/window_snapshot/snapshot_controller.cpp", "src/window_snapshot/snapshot_proxy.cpp", diff --git a/wmserver/include/window_layout_policy_cascade.h b/wmserver/include/window_layout_policy_cascade.h index ba8246e6..d624d285 100644 --- a/wmserver/include/window_layout_policy_cascade.h +++ b/wmserver/include/window_layout_policy_cascade.h @@ -40,6 +40,7 @@ public: void AddWindowNode(sptr& node) override; void UpdateWindowNode(sptr& node, bool isAddWindow = false) override; void UpdateLayoutRect(sptr& node) override; + void RemoveWindowNode(sptr& node) override; private: // Rects for split screen diff --git a/wmserver/include/window_node_container.h b/wmserver/include/window_node_container.h index 3f9ddcab..cb72d623 100644 --- a/wmserver/include/window_node_container.h +++ b/wmserver/include/window_node_container.h @@ -24,6 +24,7 @@ #include "window_zorder_policy.h" #include "wm_common.h" #include "wm_common_inner.h" +#include "window_pair.h" namespace OHOS { namespace Rosen { @@ -70,9 +71,8 @@ public: void NotifySystemBarDismiss(sptr& node); WMError MinimizeAppNodeExceptOptions(bool fromUser, const std::vector &exceptionalIds = {}, const std::vector &exceptionalModes = {}); - WMError EnterSplitWindowMode(sptr& node); - WMError ExitSplitWindowMode(sptr& node); WMError SwitchLayoutPolicy(WindowLayoutMode mode, bool reorder = false); + WMError SetWindowMode(sptr& node, WindowMode dstMode); void RaiseSplitRelatedWindowToTop(sptr& node); void MoveWindowNode(sptr& container); float GetVirtualPixelRatio() const; @@ -90,9 +90,6 @@ private: void UpdateWindowTree(sptr& node); bool UpdateRSTree(sptr& node, bool isAdd); - void SendSplitScreenEvent(sptr& node); - sptr FindSplitPairNode(sptr& node) const; - WMError UpdateWindowPairInfo(sptr& triggerNode, sptr& pairNode); void NotifyIfSystemBarTintChanged(); void NotifyIfSystemBarRegionChanged(); void TraverseAndUpdateWindowState(WindowState state, int32_t topPriority); @@ -111,7 +108,8 @@ private: void RcoveryScreenDefaultOrientationIfNeed(); // 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 orderedIds, std::vector>& windowNodes); + void RaiseOrderedWindowToTop(std::vector>& orderedNodes, + std::vector>& windowNodes); static bool ReadIsWindowAnimationEnabledProperty(); sptr avoidController_; @@ -140,12 +138,7 @@ private: float displayBrightness_ = UNDEFINED_BRIGHTNESS; // UNDEFINED_BRIGHTNESS means system default brightness uint32_t brightnessWindow_ = INVALID_WINDOW_ID; void DumpScreenWindowTree(); - - struct WindowPairInfo { - sptr pairNode_; - float splitRatio_; - }; - std::unordered_map pairedWindowMap_; + sptr windowPair_; void RaiseInputMethodWindowPriorityIfNeeded(const sptr& node) const; void RaiseShowWhenLockedWindowIfNeeded(const sptr& node); void ReZOrderShowWhenLockedWindows(const sptr& node, bool up); diff --git a/wmserver/include/window_pair.h b/wmserver/include/window_pair.h new file mode 100644 index 00000000..b7f85ee7 --- /dev/null +++ b/wmserver/include/window_pair.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 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. + */ + +#ifndef OHOS_ROSEN_WINDOW_PAIR_H +#define OHOS_ROSEN_WINDOW_PAIR_H + +#include +#include "window_inner_manager.h" +#include "window_node.h" +#include "wm_common_inner.h" +#include "wm_common.h" + +namespace OHOS { +namespace Rosen { +/** + * Enumerates the status of window pair. + */ +enum class WindowPairStatus : uint32_t { + STATUS_EMPTY, + STATUS_SINGLE_PRIMARY, + STATUS_SINGLE_SECONDARY, + STATUS_PAIRING, + STATUS_PAIRED_DONE +}; + +/** + * Enumerates the message of split event. + */ +enum class SplitBroadcastMsg : uint32_t { + MSG_NONE, + MSG_START_PRIMARY, + MSG_START_SECONDARY, + MSG_START_DIVIDER +}; + +class WindowPair : public RefBase { +public: + /** + * Constructor used to create an empty WindowPair instance. + * + * @param displayId the disply of window pair + * @param appNode the window root of app window + */ + WindowPair(const DisplayId& displayId, sptr& appNode); + + /** + * Deconstructor used to deconstruct. + * + */ + ~WindowPair(); + + /** + * Clear window pair. + * + */ + void Clear(); + + /** + * Set split ratio. + * + * @param ratio split ratio + */ + void SetSplitRatio(float ratio); + + /** + * Get split ratio. + * + * @return split ratio + */ + float GetSplitRatio() const; + + /** + * Get whether the window pair is paired.. + * + * @return the pair state of window pair + */ + bool IsPaired() const; + + /** + * Handle changes in the state of the window pair + * + * @param node trigger window node + */ + void UpdateIfSplitRelated(sptr& node); + + /** + * Handle remove window from pair. + * + * @param node target node + */ + void HandleRemoveWindow(sptr& node); + + /** + * Find window node from window pair. + * + * @param node target window node + * @return window node + */ + sptr Find(sptr& node); + + /** + * Get primary window node. + * + * @return primary window node + */ + sptr GetPrimaryWindow() const; + + /** + * Get secondary window node. + * + * @return secondary window node + */ + sptr GetSecondaryWindow() const; + + /** + * Get divider window node. + * + * @return divider window node + */ + sptr GetDividerWindow() const; + + /** + * Get pair status. + * + * @return the pair status of window pair + */ + WindowPairStatus GetPairStatus() const; + + /** + * Get all window node form pair in Z order. + * + * @return the list window form pair + */ + std::vector> GetOrderedPair(sptr& node); + + /** + * Get all window node form pair. + * + * @return the list window form pair + */ + std::vector> GetPairedWindows(); + +private: + /** + * Gets whether the window is related to split window. + * + * @param node target node + * @return Whether target node is related to the split window + */ + bool IsSplitRelated(sptr& node) const; + + /** + * Replace paired window. + * + * @param node current node + */ + void Insert(sptr& node); + + /** + * Update paired window node + * + */ + void HandlePairedNodesChange(); + + /** + * Update pair status + * + */ + void UpdateWindowPairStatus(); + + /** + * Switch the position of two paired window. + * + */ + void SwitchPosition(); + + /** + * Dump the info of pair. + * + */ + void DumpPairInfo(); + + /** + * Send inner window message. + * + * @param cmd the message of inner window manager + * @param displayId the id of target display + */ + void SendInnerMessage(InnerWMCmd cmd, DisplayId displayId); + + /** + * Find pairable window frome window trees. + * + * @param node the node waiting to be paired + * @return window node + */ + sptr FindPairableWindow(sptr& node); + + /** + * Get pairable node from trees or send split broadcast. + * + * @param node the node waiting to be paired + * @return pairable node + */ + sptr GetPairableWindow(sptr& node); + + /** + * Send brodcast message of split event. + * + * @param node trigger node + */ + void SendBroadcastMsg(sptr& node); + +private: + float ratio_ = DEFAULT_SPLIT_RATIO; + DisplayId displayId_; + sptr appWindowNode_; + sptr primary_; + sptr secondary_; + sptr divider_; + WindowPairStatus status_ = {WindowPairStatus::STATUS_EMPTY}; +}; +} // namespace Rosen +} // namespace OHOS +#endif // OHOS_ROSEN_WINDOW_PAIR_H \ No newline at end of file diff --git a/wmserver/include/window_root.h b/wmserver/include/window_root.h index 42ec42b2..dc794ad8 100644 --- a/wmserver/include/window_root.h +++ b/wmserver/include/window_root.h @@ -51,8 +51,7 @@ public: WMError RequestActiveWindow(uint32_t windowId); WMError MinimizeStructuredAppWindowsExceptSelf(sptr& node); std::vector GetAvoidAreaByType(uint32_t windowId, AvoidAreaType avoidAreaType); - WMError EnterSplitWindowMode(sptr& node); - WMError ExitSplitWindowMode(sptr& node); + WMError SetWindowMode(sptr& node, WindowMode dstMode); std::shared_ptr GetSurfaceNodeByAbilityToken(const sptr& abilityToken) const; WMError GetTopWindowId(uint32_t mainWinId, uint32_t& topWinId); void MinimizeAllAppWindows(DisplayId displayId); diff --git a/wmserver/src/window_controller.cpp b/wmserver/src/window_controller.cpp index bbf897ba..3a928312 100644 --- a/wmserver/src/window_controller.cpp +++ b/wmserver/src/window_controller.cpp @@ -219,47 +219,10 @@ WMError WindowController::SetWindowMode(uint32_t windowId, WindowMode dstMode) WLOGFE("could not find window"); return WMError::WM_ERROR_NULLPTR; } - WindowMode srcMode = node->GetWindowMode(); - if (srcMode == dstMode) { - return WMError::WM_OK; + WMError ret = windowRoot_->SetWindowMode(node, dstMode); + if (ret != WMError::WM_OK) { + return ret; } - WMError res = WMError::WM_OK; - if ((srcMode == WindowMode::WINDOW_MODE_FULLSCREEN) && (dstMode == WindowMode::WINDOW_MODE_FLOATING)) { - node->SetWindowSizeChangeReason(WindowSizeChangeReason::RECOVER); - } else if (dstMode == WindowMode::WINDOW_MODE_FULLSCREEN) { - node->SetWindowSizeChangeReason(WindowSizeChangeReason::MAXIMIZE); - } else { - node->SetWindowSizeChangeReason(WindowSizeChangeReason::RESIZE); - } - if (WindowHelper::IsSplitWindowMode(srcMode)) { - // change split mode to other - res = windowRoot_->ExitSplitWindowMode(node); - node->SetWindowMode(dstMode); - } else if (!WindowHelper::IsSplitWindowMode(srcMode) && WindowHelper::IsSplitWindowMode(dstMode)) { - // change other mode to split - node->SetWindowMode(dstMode); - res = windowRoot_->EnterSplitWindowMode(node); - } else { - node->SetWindowMode(dstMode); - } - if (res != WMError::WM_OK) { - node->GetWindowProperty()->ResumeLastWindowMode(); - return res; - } - if (node->GetWindowMode() == WindowMode::WINDOW_MODE_FULLSCREEN && - WindowHelper::IsAppWindow(node->GetWindowType())) { - // minimize other app window - res = windowRoot_->MinimizeStructuredAppWindowsExceptSelf(node); - if (res != WMError::WM_OK) { - return res; - } - } - res = windowRoot_->UpdateWindowNode(windowId, WindowUpdateReason::UPDATE_MODE); - if (res != WMError::WM_OK) { - WLOGFE("Set window mode failed, update node failed"); - return res; - } - node->GetWindowToken()->UpdateWindowMode(node->GetWindowMode()); FlushWindowInfo(windowId); return WMError::WM_OK; } diff --git a/wmserver/src/window_layout_policy_cascade.cpp b/wmserver/src/window_layout_policy_cascade.cpp index aa8d4a85..83ea89c3 100644 --- a/wmserver/src/window_layout_policy_cascade.cpp +++ b/wmserver/src/window_layout_policy_cascade.cpp @@ -87,6 +87,21 @@ void WindowLayoutPolicyCascade::LayoutWindowTree() WindowLayoutPolicy::LayoutWindowTree(); } +void WindowLayoutPolicyCascade::RemoveWindowNode(sptr& node) +{ + WM_FUNCTION_TRACE(); + auto type = node->GetWindowType(); + // affect other windows, trigger off global layout + if (avoidTypes_.find(type) != avoidTypes_.end()) { + LayoutWindowTree(); + } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode + InitSplitRects(); + LayoutWindowTree(); + } + Rect reqRect = node->GetRequestRect(); + node->GetWindowToken()->UpdateWindowRect(reqRect, node->GetDecoStatus(), WindowSizeChangeReason::HIDE); +} + void WindowLayoutPolicyCascade::UpdateWindowNode(sptr& node, bool isAddWindow) { WM_FUNCTION_TRACE(); @@ -109,6 +124,8 @@ void WindowLayoutPolicyCascade::UpdateWindowNode(sptr& node, bool is } } LayoutWindowTree(); + } else if (node->IsSplitMode()) { + LayoutWindowTree(); } else { // layout single window LayoutWindowNode(node); } @@ -159,7 +176,7 @@ void WindowLayoutPolicyCascade::LimitMoveBounds(Rect& rect) const void WindowLayoutPolicyCascade::InitCascadeRect() { constexpr uint32_t half = 2; - constexpr float ratio = 0.75; // 0.75: default height/width ratio + constexpr float ratio = 0.66; // 0.66: default height/width ratio // calculate default H and w uint32_t defaultW = static_cast(displayRect_.width_ * ratio); diff --git a/wmserver/src/window_layout_policy_tile.cpp b/wmserver/src/window_layout_policy_tile.cpp index cf0a97a8..04b74c96 100644 --- a/wmserver/src/window_layout_policy_tile.cpp +++ b/wmserver/src/window_layout_policy_tile.cpp @@ -272,4 +272,4 @@ void WindowLayoutPolicyTile::UpdateLayoutRect(sptr& node) } } } // Rosen -} // OHOS \ No newline at end of file +} // OHOS diff --git a/wmserver/src/window_node_container.cpp b/wmserver/src/window_node_container.cpp index 3645c20c..71aed97c 100644 --- a/wmserver/src/window_node_container.cpp +++ b/wmserver/src/window_node_container.cpp @@ -53,6 +53,7 @@ WindowNodeContainer::WindowNodeContainer(DisplayId displayId, uint32_t width, ui .width_ = width, .height_ = height }; + windowPair_ = new WindowPair(displayId_, appWindowNode_); layoutPolicys_[WindowLayoutMode::CASCADE] = new WindowLayoutPolicyCascade(displayRect_, displayId_, belowAppWindowNode_, appWindowNode_, aboveAppWindowNode_); @@ -118,14 +119,7 @@ WMError WindowNodeContainer::AddWindowNode(sptr& node, sptrparent_ = parentNode; - - if (node->IsSplitMode()) { - WMError ret = EnterSplitWindowMode(node); - if (ret != WMError::WM_OK) { - WLOGFE("Add split window failed!"); - return ret; - } - } + windowPair_->UpdateIfSplitRelated(node); UpdateWindowTree(node); if (node->IsSplitMode() || node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) { RaiseSplitRelatedWindowToTop(node); @@ -295,17 +289,9 @@ WMError WindowNodeContainer::RemoveWindowNode(sptr& node) child->GetCallingUid(), false)); } } - - if (node->IsSplitMode()) { - WMError ret = ExitSplitWindowMode(node); - if (ret != WMError::WM_OK) { - WLOGFE("Remove split window failed!"); - return ret; - } - } - UpdateRSTree(node, false); layoutPolicy_->RemoveWindowNode(node); + windowPair_->HandleRemoveWindow(node); if (WindowHelper::IsAvoidAreaWindow(node->GetWindowType())) { avoidController_->AvoidControl(node, AvoidControlType::AVOID_NODE_REMOVE); NotifyIfSystemBarRegionChanged(); @@ -706,23 +692,22 @@ bool WindowNodeContainer::IsTopWindow(uint32_t windowId, sptr& rootN return node->GetWindowId() == windowId; } -void WindowNodeContainer::RaiseOrderedWindowToTop(std::vector orderedIds, +void WindowNodeContainer::RaiseOrderedWindowToTop(std::vector>& orderedNodes, std::vector>& windowNodes) { for (auto iter = appWindowNode_->children_.begin(); iter != appWindowNode_->children_.end();) { uint32_t wid = (*iter)->GetWindowId(); - auto idIter = std::find_if(orderedIds.begin(), orderedIds.end(), - [wid] (uint32_t id) { return id == wid; }); - if (idIter != orderedIds.end()) { - orderedIds.erase(idIter); - sptr node = *iter; + auto orderedIter = std::find_if(orderedNodes.begin(), orderedNodes.end(), + [wid] (sptr orderedNode) { return orderedNode->GetWindowId() == wid; }); + if (orderedIter != orderedNodes.end()) { iter = windowNodes.erase(iter); - UpdateWindowTree(node); - WLOGFI("raise group window to top %{public}u", node->GetWindowId()); } else { iter++; } } + for (auto iter = orderedNodes.begin(); iter != orderedNodes.end(); iter++) { + UpdateWindowTree(*iter); + } return; } @@ -956,36 +941,8 @@ void WindowNodeContainer::RaiseSplitRelatedWindowToTop(sptr& node) if (node == nullptr) { return; } - if (!node->IsSplitMode() && node->GetWindowType() != WindowType::WINDOW_TYPE_DOCK_SLICE) { - return; - } - if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE && !pairedWindowMap_.empty()) { - std::vector raiseNodeIds; - for (auto& splitInfo : pairedWindowMap_) { - auto pairNode = splitInfo.second.pairNode_; - if (pairNode != nullptr) { - raiseNodeIds.push_back(pairNode->GetWindowId()); - } - } - // raise primary and secondary window to top, keep raw zorder - RaiseOrderedWindowToTop(raiseNodeIds, appWindowNode_->children_); - // raise divider final, keep divider on top - RaiseWindowToTop(node->GetWindowId(), appWindowNode_->children_); - } else if (!pairedWindowMap_.empty()) { - if (pairedWindowMap_.count(node->GetWindowId())) { - auto pairNode = pairedWindowMap_.at(node->GetWindowId()).pairNode_; - RaiseWindowToTop(pairNode->GetWindowId(), appWindowNode_->children_); - } - RaiseWindowToTop(node->GetWindowId(), appWindowNode_->children_); - sptr deviderNode = FindDividerNode(); - if (deviderNode != nullptr) { - // raise divider final, keep divider on top - RaiseWindowToTop(deviderNode->GetWindowId(), appWindowNode_->children_); - } - } else { - // raise self if not paired - RaiseWindowToTop(node->GetWindowId(), appWindowNode_->children_); - } + std::vector> orderedPair = windowPair_->GetOrderedPair(node); + RaiseOrderedWindowToTop(orderedPair, appWindowNode_->children_); AssignZOrder(); return; } @@ -1100,46 +1057,6 @@ void WindowNodeContainer::MinimizeAllAppWindows() return; } -void WindowNodeContainer::SendSplitScreenEvent(sptr& node) -{ - // reset ipc identity - std::string identity = IPCSkeleton::ResetCallingIdentity(); - AAFwk::Want want; - want.SetAction(SPLIT_SCREEN_EVENT_NAME); - std::string modeData = (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) ? "Secondary" : "Primary"; - int32_t missionId = -1; - AAFwk::AbilityManagerClient::GetInstance()->GetMissionIdByToken(node->abilityToken_, missionId); - WLOGFI("split window missionId is: %{public}d", missionId); - want.SetParam("windowMode", modeData); - want.SetParam("missionId", missionId); - EventFwk::CommonEventData commonEventData; - commonEventData.SetWant(want); - EventFwk::CommonEventManager::PublishCommonEvent(commonEventData); - // set ipc identity to raw - IPCSkeleton::SetCallingIdentity(identity); - WLOGFI("send split sceen event finish."); -} - -sptr WindowNodeContainer::FindSplitPairNode(sptr& triggerNode) const -{ - auto triggerMode = triggerNode->GetWindowMode(); - for (auto iter = appWindowNode_->children_.rbegin(); iter != appWindowNode_->children_.rend(); iter++) { - if ((*iter)->GetWindowId() == triggerNode->GetWindowId()) { - continue; - } - // Find Top FullScreen main winodow or top paired split mode app main window - if ((*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_FULLSCREEN || - (triggerMode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY && - (*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) || - (triggerMode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY && - (*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY)) { - WLOGFI("Find pair node mode is: %{public}d", static_cast((*iter)->GetWindowMode())); - return *iter; - } - } - return nullptr; -} - void WindowNodeContainer::MinimizeWindowFromAbility(const sptr& node, bool fromUser) { if (node->abilityToken_ == nullptr) { @@ -1170,105 +1087,11 @@ WMError WindowNodeContainer::MinimizeAppNodeExceptOptions(bool fromUser, const s return WMError::WM_OK; } -WMError WindowNodeContainer::EnterSplitWindowMode(sptr& node) -{ - WM_FUNCTION_TRACE(); - WLOGFI("Enter split window mode: %{public}u", node->GetWindowId()); - SwitchLayoutPolicy(WindowLayoutMode::CASCADE); // window split mode is belong to cascade - auto pairNode = FindSplitPairNode(node); - if (pairNode != nullptr) { - WLOGFI("Window %{public}d find pair %{public}u", node->GetWindowId(), pairNode->GetWindowId()); - WMError ret = UpdateWindowPairInfo(node, pairNode); - if (ret != WMError::WM_OK) { - return ret; - } - SingletonContainer::Get().SendMessage(InnerWMCmd::INNER_WM_CREATE_DIVIDER, displayId_); - std::vector exceptionalIds; - for (auto iter = pairedWindowMap_.begin(); iter != pairedWindowMap_.end(); iter++) { - exceptionalIds.emplace_back(iter->first); - } - std::vector exceptionalModes = { WindowMode::WINDOW_MODE_FLOATING, WindowMode::WINDOW_MODE_PIP }; - ret = MinimizeAppNodeExceptOptions(false, exceptionalIds, exceptionalModes); - if (ret != WMError::WM_OK) { - return ret; - } - } else { - SendSplitScreenEvent(node); - } - return WMError::WM_OK; -} - void WindowNodeContainer::ResetLayoutPolicy() { layoutPolicy_->Reset(); } -WMError WindowNodeContainer::ExitSplitWindowMode(sptr& node) -{ - WM_FUNCTION_TRACE(); - WLOGFI("exit split window mode %{public}u", node->GetWindowId()); - node->GetWindowProperty()->ResumeLastWindowMode(); - node->GetWindowToken()->UpdateWindowMode(node->GetWindowMode()); - if (pairedWindowMap_.count(node->GetWindowId()) != 0) { - auto pairNode = pairedWindowMap_.at(node->GetWindowId()).pairNode_; - pairNode->GetWindowProperty()->ResumeLastWindowMode(); - pairNode->GetWindowToken()->UpdateWindowMode(pairNode->GetWindowMode()); - pairedWindowMap_.erase(pairNode->GetWindowId()); - pairedWindowMap_.erase(node->GetWindowId()); - WLOGFI("resume pair node mode, Id[%{public}u, %{public}u], Mode[%{public}d, %{public}d]", node->GetWindowId(), - pairNode->GetWindowId(), node->GetWindowMode(), pairNode->GetWindowMode()); - } - if (pairedWindowMap_.empty()) { - WLOGFI("send destroy msg to divider, Id: %{public}u", node->GetWindowId()); - SingletonContainer::Get().SendMessage(InnerWMCmd::INNER_WM_DESTROY_DIVIDER, displayId_); - } - ResetLayoutPolicy(); - return WMError::WM_OK; -} - -WMError WindowNodeContainer::UpdateWindowPairInfo(sptr& triggerNode, sptr& pairNode) -{ - float splitRatio = DEFAULT_SPLIT_RATIO; - WindowMode triggerMode = triggerNode->GetWindowMode(); - WindowMode pairSrcMode = pairNode->GetWindowMode(); - if (pairSrcMode == WindowMode::WINDOW_MODE_FULLSCREEN) { - WindowMode pairDstMode = (triggerMode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) ? - WindowMode::WINDOW_MODE_SPLIT_SECONDARY : WindowMode::WINDOW_MODE_SPLIT_PRIMARY; - pairNode->SetWindowMode(pairDstMode); - pairNode->GetWindowToken()->UpdateWindowMode(pairDstMode); - WMError ret = UpdateWindowNode(pairNode, WindowUpdateReason::UPDATE_MODE); - if (ret != WMError::WM_OK) { - WLOGFE("Update window pair info failed"); - return ret; - } - WLOGFI("Pair FullScreen [%{public}u, %{public}u], Mode[%{public}d, %{public}d], splitRatio = %{public}f", - triggerNode->GetWindowId(), pairNode->GetWindowId(), triggerMode, pairDstMode, splitRatio); - } else { - if (pairedWindowMap_.count(pairNode->GetWindowId()) != 0) { - WindowPairInfo info = pairedWindowMap_.at(pairNode->GetWindowId()); - auto prevPairNode = info.pairNode_; - WLOGFI("%{public}d node is paird , pre paired id is %{public}d,", - pairNode->GetWindowId(), prevPairNode->GetWindowId()); - prevPairNode->GetWindowProperty()->ResumeLastWindowMode(); - prevPairNode->GetWindowToken()->UpdateWindowMode(prevPairNode->GetWindowMode()); - - pairedWindowMap_.erase(prevPairNode->GetWindowId()); - pairedWindowMap_.erase(pairNode->GetWindowId()); - - splitRatio = info.splitRatio_; - WLOGFI("Pair Split [%{public}d, %{public}d], Mode[%{public}d, %{public}d], splitRatio = %{public}f", - triggerNode->GetWindowId(), pairNode->GetWindowId(), triggerMode, pairSrcMode, splitRatio); - } else { - WLOGFI("%{public}d node is not paird", pairNode->GetWindowId()); - } - } - pairedWindowMap_.insert(std::pair(triggerNode->GetWindowId(), - {pairNode, splitRatio})); - pairedWindowMap_.insert(std::pair(pairNode->GetWindowId(), - {triggerNode, 1 - splitRatio})); - return WMError::WM_OK; -} - WMError WindowNodeContainer::SwitchLayoutPolicy(WindowLayoutMode dstMode, bool reorder) { WLOGFI("SwitchLayoutPolicy src: %{public}d dst: %{public}d reorder: %{public}d", @@ -1278,9 +1101,9 @@ WMError WindowNodeContainer::SwitchLayoutPolicy(WindowLayoutMode dstMode, bool r return WMError::WM_ERROR_INVALID_PARAM; } if (layoutMode_ != dstMode) { - if (layoutMode_ == WindowLayoutMode::CASCADE && !pairedWindowMap_.empty()) { - pairedWindowMap_.clear(); - SingletonContainer::Get().SendMessage(InnerWMCmd::INNER_WM_DESTROY_DIVIDER, displayId_); + if (layoutMode_ == WindowLayoutMode::CASCADE) { + layoutPolicy_->Reset(); + windowPair_->Clear(); } layoutMode_ = dstMode; layoutPolicy_->Clean(); @@ -1291,11 +1114,7 @@ WMError WindowNodeContainer::SwitchLayoutPolicy(WindowLayoutMode dstMode, bool r WLOGFI("Current layout mode is already: %{public}d", static_cast(dstMode)); } if (reorder) { - if (!pairedWindowMap_.empty()) { - // exit divider window when reorder - pairedWindowMap_.clear(); - SingletonContainer::Get().SendMessage(InnerWMCmd::INNER_WM_DESTROY_DIVIDER, displayId_); - } + windowPair_->Clear(); layoutPolicy_->Reorder(); DumpScreenWindowTree(); } @@ -1535,5 +1354,44 @@ bool WindowNodeContainer::ReadIsWindowAnimationEnabledProperty() } return true; } + +WMError WindowNodeContainer::SetWindowMode(sptr& node, WindowMode dstMode) +{ + if (node == nullptr) { + WLOGFE("could not find window"); + return WMError::WM_ERROR_NULLPTR; + } + WindowMode srcMode = node->GetWindowMode(); + if (srcMode == dstMode) { + return WMError::WM_OK; + } + WMError res = WMError::WM_OK; + if ((srcMode == WindowMode::WINDOW_MODE_FULLSCREEN) && (dstMode == WindowMode::WINDOW_MODE_FLOATING)) { + node->SetWindowSizeChangeReason(WindowSizeChangeReason::RECOVER); + } else if (dstMode == WindowMode::WINDOW_MODE_FULLSCREEN) { + node->SetWindowSizeChangeReason(WindowSizeChangeReason::MAXIMIZE); + } else { + node->SetWindowSizeChangeReason(WindowSizeChangeReason::RESIZE); + } + node->SetWindowMode(dstMode); + windowPair_->UpdateIfSplitRelated(node); + if (node->GetWindowMode() == WindowMode::WINDOW_MODE_FULLSCREEN && + WindowHelper::IsAppWindow(node->GetWindowType())) { + // minimize other app window + res = MinimizeStructuredAppWindowsExceptSelf(node); + if (res != WMError::WM_OK) { + return res; + } + } + if (node->GetWindowToken() != nullptr) { + node->GetWindowToken()->UpdateWindowMode(node->GetWindowMode()); + } + res = UpdateWindowNode(node, WindowUpdateReason::UPDATE_MODE); + if (res != WMError::WM_OK) { + WLOGFE("Set window mode failed, update node failed"); + return res; + } + return WMError::WM_OK; +} } // namespace Rosen } // namespace OHOS diff --git a/wmserver/src/window_pair.cpp b/wmserver/src/window_pair.cpp new file mode 100644 index 00000000..05622073 --- /dev/null +++ b/wmserver/src/window_pair.cpp @@ -0,0 +1,431 @@ +/* + * Copyright (c) 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 "window_pair.h" + +#include +#include "common_event_manager.h" +#include "window_manager_hilog.h" +#include "window_helper.h" +#include "wm_trace.h" + +namespace OHOS { +namespace Rosen { +namespace { + constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowPair"}; + const std::string SPLIT_SCREEN_EVENT_NAME = "common.event.SPLIT_SCREEN"; +} + +WindowPair::WindowPair(const DisplayId& displayId, sptr& appNode) + : displayId_(displayId), appWindowNode_(appNode) { +} + +WindowPair::~WindowPair() +{ + WLOGI("~WindowPair"); + Clear(); +} + +void WindowPair::SendInnerMessage(InnerWMCmd cmd, DisplayId displayId) +{ + WLOGI("Send inner message cmd id: %{public}u display id: %{public}u.", static_cast(cmd), + static_cast(displayId)); + SingletonContainer::Get().SendMessage(cmd, displayId); +} + +void WindowPair::SendBroadcastMsg(sptr& node) +{ + if (node == nullptr) { + return; + } + // reset ipc identity + std::string identity = IPCSkeleton::ResetCallingIdentity(); + AAFwk::Want want; + want.SetAction(SPLIT_SCREEN_EVENT_NAME); + int32_t missionId = -1; + AAFwk::AbilityManagerClient::GetInstance()->GetMissionIdByToken(node->abilityToken_, missionId); + std::string modeData = ""; + auto msg = (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) ? + SplitBroadcastMsg::MSG_START_PRIMARY : SplitBroadcastMsg::MSG_START_SECONDARY; + switch (msg) { + case SplitBroadcastMsg::MSG_START_PRIMARY : + modeData = "Primary"; + break; + case SplitBroadcastMsg::MSG_START_SECONDARY : + modeData = "Secondary"; + break; + case SplitBroadcastMsg::MSG_START_DIVIDER : + modeData = "Divider"; + break; + default: + break; + } + want.SetParam("windowMode", modeData); + want.SetParam("missionId", missionId); + EventFwk::CommonEventData commonEventData; + commonEventData.SetWant(want); + EventFwk::CommonEventManager::PublishCommonEvent(commonEventData); + // set ipc identity to raw + IPCSkeleton::SetCallingIdentity(identity); + WLOGI("Send broadcast msg: %{public}s", modeData.c_str()); +} + +sptr WindowPair::Find(sptr& node) +{ + if (node == nullptr) { + return nullptr; + } + if (primary_ != nullptr && primary_->GetWindowId() == node->GetWindowId()) { + return primary_; + } else if (secondary_ != nullptr && secondary_->GetWindowId() == node->GetWindowId()) { + return secondary_; + } else if (divider_ != nullptr && divider_->GetWindowId() == node->GetWindowId()) { + return divider_; + } + return nullptr; +} + +bool WindowPair::IsPaired() const +{ + if (primary_ == nullptr || secondary_ == nullptr) { + return false; + } + if (primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY && + secondary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY && + divider_ != nullptr) { + return true; + } + return false; +} + +void WindowPair::SetSplitRatio(float ratio) +{ + ratio_ = ratio; +} + +float WindowPair::GetSplitRatio() const +{ + return ratio_; +} + +WindowPairStatus WindowPair::GetPairStatus() const +{ + return status_; +} + +sptr WindowPair::GetDividerWindow() const +{ + return divider_; +} + +sptr WindowPair::GetPrimaryWindow() const +{ + return primary_; +} + +sptr WindowPair::GetSecondaryWindow() const +{ + return secondary_; +} + +void WindowPair::Clear() +{ + WLOGI("Clear window pair."); + DumpPairInfo(); + if (primary_ != nullptr && primary_->GetWindowProperty() != nullptr && + primary_->GetWindowToken() != nullptr) { + primary_->GetWindowProperty()->ResumeLastWindowMode(); + primary_->GetWindowToken()->UpdateWindowMode(primary_->GetWindowMode()); + } + if (secondary_ != nullptr && secondary_->GetWindowProperty() != nullptr && + secondary_->GetWindowToken() != nullptr) { + secondary_->GetWindowProperty()->ResumeLastWindowMode(); + secondary_->GetWindowToken()->UpdateWindowMode(secondary_->GetWindowMode()); + } + primary_ = nullptr; + secondary_ = nullptr; + if (divider_ != nullptr) { + SendInnerMessage(InnerWMCmd::INNER_WM_DESTROY_DIVIDER, displayId_); + divider_ = nullptr; + } + status_ = WindowPairStatus::STATUS_EMPTY; +} + +bool WindowPair::IsSplitRelated(sptr& node) const +{ + if (node == nullptr) { + return false; + } + return WindowHelper::IsSplitWindowMode((node->GetWindowMode())) || + (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE); +} + +std::vector> WindowPair::GetOrderedPair(sptr& node) +{ + WLOGI("Get piared node in Z order"); + std::vector> orderedPair; + if (node == nullptr || Find(node) == nullptr) { + return orderedPair; + } + if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY || + node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) { + // primary secondary + if (primary_ != nullptr && WindowHelper::IsAppWindow(primary_->GetWindowType())) { + orderedPair.push_back(primary_); + } + if (secondary_ != nullptr && WindowHelper::IsAppWindow(secondary_->GetWindowType())) { + orderedPair.push_back(secondary_); + } + } else if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) { + // secondary primary divider + if (secondary_ != nullptr && WindowHelper::IsAppWindow(secondary_->GetWindowType())) { + orderedPair.push_back(secondary_); + } + if (primary_ != nullptr && WindowHelper::IsAppWindow(primary_->GetWindowType())) { + orderedPair.push_back(primary_); + } + } + if (divider_ != nullptr) { + orderedPair.push_back(divider_); + } + return orderedPair; +} + +std::vector> WindowPair::GetPairedWindows() +{ + WLOGI("Get all node of window pair"); + std::vector> orderedPair; + if (primary_ != nullptr) { + orderedPair.push_back(primary_); + } + if (secondary_ != nullptr) { + orderedPair.push_back(secondary_); + } + if (divider_ != nullptr) { + orderedPair.push_back(divider_); + } + return orderedPair; +} + +sptr WindowPair::FindPairableWindow(sptr& node) +{ + if (node == nullptr) { + return nullptr; + } + if (!node->IsSplitMode()) { + return nullptr; + } + for (auto iter = appWindowNode_->children_.rbegin(); iter != appWindowNode_->children_.rend(); iter++) { + auto pairNode = *iter; + if (pairNode == nullptr) { + continue; + } + if (pairNode->GetWindowMode() == WindowMode::WINDOW_MODE_FULLSCREEN) { + WindowMode dstMode = (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ? + WindowMode::WINDOW_MODE_SPLIT_SECONDARY : WindowMode::WINDOW_MODE_SPLIT_PRIMARY); + pairNode->SetWindowMode(dstMode); + if (pairNode->GetWindowToken() != nullptr) { + pairNode->GetWindowToken()->UpdateWindowMode(pairNode->GetWindowMode()); + } + WLOGFI("Find full screen pair window: %{public}u", static_cast(pairNode->GetWindowId())); + return pairNode; + } + } + return nullptr; +} + +sptr WindowPair::GetPairableWindow(sptr& node) +{ + if (node == nullptr) { + return nullptr; + } + // get pairable window from window tree or send broadcast msg to start pair window + sptr pairableNode = FindPairableWindow(node); + if (pairableNode == nullptr) { + WLOGFI("Can not find pairable window from current tree."); + SendBroadcastMsg(node); + return nullptr; + } + WLOGFI("Find pairable window id: %{public}u", pairableNode->GetWindowId()); + return pairableNode; +} + + +void WindowPair::UpdateIfSplitRelated(sptr& node) +{ + if (node == nullptr) { + WLOGI("Window is nullptr."); + return; + } + if (Find(node) == nullptr && !IsSplitRelated(node)) { + WLOGI("Window id: %{public}u is not split related and paired.", node->GetWindowId()); + return; + } + WLOGI("Current status: %{public}u, window id: %{public}u mode: %{public}u", + status_, node->GetWindowId(), node->GetWindowMode()); + if (status_ == WindowPairStatus::STATUS_EMPTY) { + Insert(node); + // find pairable window from trees or send broadcast + sptr pairableNode = GetPairableWindow(node); + // insert pairable node + Insert(pairableNode); + } else { + if (Find(node) == nullptr) { + // add new split related node to pair + Insert(node); + } else { + // handle paired nodes change + HandlePairedNodesChange(); + } + } +} + +void WindowPair::UpdateWindowPairStatus() +{ + WLOGI("Update window pair status."); + WindowPairStatus prevStatus = status_; + if (primary_ != nullptr && secondary_ != nullptr && divider_ != nullptr) { + status_ = WindowPairStatus::STATUS_PAIRED_DONE; + } else if (primary_ != nullptr && secondary_ != nullptr && divider_ == nullptr) { + status_ = WindowPairStatus::STATUS_PAIRING; + } else if (primary_ != nullptr && secondary_ == nullptr) { + status_ = WindowPairStatus::STATUS_SINGLE_PRIMARY; + } else if (primary_ == nullptr && secondary_ != nullptr) { + status_ = WindowPairStatus::STATUS_SINGLE_SECONDARY; + } else { + status_ = WindowPairStatus::STATUS_EMPTY; + } + if ((prevStatus == WindowPairStatus::STATUS_SINGLE_PRIMARY || + prevStatus == WindowPairStatus::STATUS_SINGLE_SECONDARY || prevStatus == WindowPairStatus::STATUS_EMPTY) && + status_ == WindowPairStatus::STATUS_PAIRING) { + // create divider + SendInnerMessage(InnerWMCmd::INNER_WM_CREATE_DIVIDER, displayId_); + } else if ((prevStatus == WindowPairStatus::STATUS_PAIRED_DONE || prevStatus == WindowPairStatus::STATUS_PAIRING) && + (status_ != WindowPairStatus::STATUS_PAIRED_DONE && status_ != WindowPairStatus::STATUS_PAIRING)) { + // clear pair + Clear(); + } + DumpPairInfo(); +} + +void WindowPair::SwitchPosition() +{ + if (primary_ == nullptr || secondary_ == nullptr) { + return; + } + WLOGFI("Switch the pair pos, pri: %{public}u pri-mode: %{public}u, sec: %{public}u sec-mode: %{public}u,", + primary_->GetWindowId(), primary_->GetWindowMode(), secondary_->GetWindowId(), secondary_->GetWindowMode()); + if (primary_->GetWindowMode() == secondary_->GetWindowMode() && + primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) { + primary_->SetWindowMode(WindowMode::WINDOW_MODE_SPLIT_SECONDARY); + if (primary_->GetWindowToken() != nullptr) { + primary_->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_SPLIT_SECONDARY); + } + std::swap(primary_, secondary_); + } else if (primary_->GetWindowMode() == secondary_->GetWindowMode() && + primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) { + secondary_->SetWindowMode(WindowMode::WINDOW_MODE_SPLIT_PRIMARY); + if (secondary_->GetWindowToken() != nullptr) { + secondary_->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_SPLIT_PRIMARY); + } + std::swap(primary_, secondary_); + } +} + +void WindowPair::HandlePairedNodesChange() +{ + WLOGI("Update pair node."); + if (primary_ != nullptr && !primary_->IsSplitMode()) { + primary_ = nullptr; + } + if (secondary_ != nullptr && !secondary_->IsSplitMode()) { + secondary_ = nullptr; + } + // paired node mode change + if (primary_ != nullptr && secondary_ == nullptr && + primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) { + std::swap(primary_, secondary_); + } else if (primary_ == nullptr && secondary_ != nullptr && + secondary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) { + std::swap(primary_, secondary_); + } else if (primary_ != nullptr && secondary_ != nullptr && + primary_->GetWindowMode() == secondary_->GetWindowMode()) { + // switch position + SwitchPosition(); + } + UpdateWindowPairStatus(); +} + +void WindowPair::Insert(sptr& node) +{ + if (node == nullptr) { + return; + } + WLOGI("Insert a window to pair id: %{public}u", node->GetWindowId()); + sptr pairedNode; + if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) { + pairedNode = primary_; + primary_ = node; + } else if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) { + pairedNode = secondary_; + secondary_ = node; + } else if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) { + pairedNode = divider_; + divider_ = node; + } + // minimize invalid paired window + if (pairedNode != nullptr && pairedNode->abilityToken_ != nullptr) { + AAFwk::AbilityManagerClient::GetInstance()->MinimizeAbility(pairedNode->abilityToken_, false); + } + UpdateWindowPairStatus(); +} + +void WindowPair::DumpPairInfo() +{ + if (primary_ != nullptr) { + WLOGI("[DumpPairInfo] primary id: %{public}u mode: %{public}u", primary_->GetWindowId(), + primary_->GetWindowMode()); + } + if (secondary_ != nullptr) { + WLOGI("[DumpPairInfo] secondary id: %{public}u mode: %{public}u", secondary_->GetWindowId(), + secondary_->GetWindowMode()); + } + if (divider_ != nullptr) { + WLOGI("[DumpPairInfo] divider id: %{public}u mode: %{public}u", divider_->GetWindowId(), + divider_->GetWindowMode()); + } + WLOGI("[DumpPairInfo] pair status %{public}u", status_); +} + +void WindowPair::HandleRemoveWindow(sptr& node) +{ + if (node == nullptr) { + return; + } + if (Find(node) == nullptr && node->IsSplitMode()) { + WLOGI("Resume unpaired split related window id: %{public}u", node->GetWindowId()); + if (node->GetWindowProperty() != nullptr && node->GetWindowToken() != nullptr) { + node->GetWindowProperty()->ResumeLastWindowMode(); + node->GetWindowToken()->UpdateWindowMode(node->GetWindowMode()); + } + // target node is not in window pair, need resume mode when remove + return; + } else if (Find(node) != nullptr) { + WLOGI("Pairing window id: %{public}u is remove, clear window pair", node->GetWindowId()); + Clear(); + } +} +} // namespace Rosen +} // namespace OHOS \ No newline at end of file diff --git a/wmserver/src/window_root.cpp b/wmserver/src/window_root.cpp index f6633550..326ccce4 100644 --- a/wmserver/src/window_root.cpp +++ b/wmserver/src/window_root.cpp @@ -361,24 +361,14 @@ void WindowRoot::UpdateFocusableProperty(uint32_t windowId) } } -WMError WindowRoot::EnterSplitWindowMode(sptr& node) +WMError WindowRoot::SetWindowMode(sptr& node, WindowMode dstMode) { auto container = GetOrCreateWindowNodeContainer(node->GetDisplayId()); if (container == nullptr) { - WLOGFE("Enter split window mode failed, window container could not be found"); + WLOGFE("set window mode failed, window container could not be found"); return WMError::WM_ERROR_NULLPTR; } - return container->EnterSplitWindowMode(node); -} - -WMError WindowRoot::ExitSplitWindowMode(sptr& node) -{ - auto container = GetOrCreateWindowNodeContainer(node->GetDisplayId()); - if (container == nullptr) { - WLOGFE("Exit split window mode failed, window container could not be found"); - return WMError::WM_ERROR_NULLPTR; - } - return container->ExitSplitWindowMode(node); + return container->SetWindowMode(node, dstMode); } WMError WindowRoot::DestroyWindow(uint32_t windowId, bool onlySelf)