1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "minimize_app.h"
17
18#include <ability_manager_client.h>
19#include "window_manager_hilog.h"
20#include "window_inner_manager.h"
21
22namespace OHOS {
23namespace Rosen {
24namespace {
25constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "MinimizeApp"};
26}
27
28std::map<MinimizeReason, std::vector<wptr<WindowNode>>> MinimizeApp::needMinimizeAppNodes_;
29bool MinimizeApp::isMinimizedByOtherWindow_ = true;
30std::recursive_mutex MinimizeApp::mutex_;
31void MinimizeApp::AddNeedMinimizeApp(const sptr<WindowNode>& node, MinimizeReason reason)
32{
33    std::lock_guard<std::recursive_mutex> lock(mutex_);
34    if (!EnableMinimize(reason)) {
35        return;
36    }
37    if (!node) {
38        WLOGFE("AddNeedMinimizeApp failed since node is nullptr");
39        return;
40    }
41    wptr<WindowNode> weakNode(node);
42    for (auto& appNodes: needMinimizeAppNodes_) {
43        auto windowId = node->GetWindowId();
44        auto iter = std::find_if(appNodes.second.begin(), appNodes.second.end(),
45            [windowId](wptr<WindowNode> srcNode) {
46                auto weakSrcNode = srcNode.promote();
47                if (weakSrcNode == nullptr) {
48                    return false;
49                }
50                return weakSrcNode->GetWindowId() == windowId;
51            });
52        if (iter != appNodes.second.end()) {
53            WLOGI("[Minimize] Window %{public}u is already in minimize list", node->GetWindowId());
54            return;
55        }
56    }
57    WLOGI("[Minimize] Add Window %{public}u to minimize list, reason %{public}u", node->GetWindowId(), reason);
58    needMinimizeAppNodes_[reason].emplace_back(weakNode);
59}
60
61std::vector<wptr<WindowNode>> MinimizeApp::GetNeedMinimizeAppNodesWithReason(MinimizeReason reason)
62{
63    std::lock_guard<std::recursive_mutex> lock(mutex_);
64    std::vector<wptr<WindowNode>> needMinimizeAppNodes;
65    if (needMinimizeAppNodes_.find(reason) != needMinimizeAppNodes_.end()) {
66        for (auto& node : needMinimizeAppNodes_[reason]) {
67            needMinimizeAppNodes.emplace_back(node);
68        }
69    }
70    return needMinimizeAppNodes;
71}
72
73void MinimizeApp::ExecuteMinimizeAll()
74{
75    std::lock_guard<std::recursive_mutex> lock(mutex_);
76    for (auto& appNodes: needMinimizeAppNodes_) {
77        bool isFromUser = IsFromUser(appNodes.first);
78        WLOGI("[Minimize] ExecuteMinimizeAll with size: %{public}zu, reason: %{public}u",
79            appNodes.second.size(), appNodes.first);
80        for (auto& node : appNodes.second) {
81            WindowInnerManager::GetInstance().MinimizeAbility(node, isFromUser);
82        }
83        appNodes.second.clear();
84    }
85    needMinimizeAppNodes_.clear();
86}
87
88void MinimizeApp::ClearNodesWithReason(MinimizeReason reason)
89{
90    WLOGI("[Minimize] ClearNodesWithReason reason %{public}u", reason);
91    std::lock_guard<std::recursive_mutex> lock(mutex_);
92    if (needMinimizeAppNodes_.find(reason) != needMinimizeAppNodes_.end()) {
93        needMinimizeAppNodes_.at(reason).clear();
94    }
95}
96
97sptr<WindowNode> MinimizeApp::GetRecoverdNodeFromMinimizeList()
98{
99    WLOGI("[Minimize] RevertMinimizedNodeForTile");
100    std::lock_guard<std::recursive_mutex> lock(mutex_);
101    if (needMinimizeAppNodes_.find(MinimizeReason::LAYOUT_TILE) != needMinimizeAppNodes_.end()) {
102        auto& tileNodesForMinimize = needMinimizeAppNodes_.at(MinimizeReason::LAYOUT_TILE);
103        if (!tileNodesForMinimize.empty()) {
104            auto recoverNode = tileNodesForMinimize.back().promote();
105            tileNodesForMinimize.pop_back();
106            return recoverNode;
107        }
108    }
109    return nullptr;
110}
111
112bool MinimizeApp::IsNodeNeedMinimize(const sptr<WindowNode>& node)
113{
114    if (node == nullptr) {
115        WLOGFE("[Minimize] node is nullptr");
116        return false;
117    }
118    for (auto iter : needMinimizeAppNodes_) {
119        auto nodes = iter.second;
120        if (std::find(nodes.begin(), nodes.end(), node) != nodes.end()) {
121            return true;
122        }
123    }
124    return false;
125}
126
127bool MinimizeApp::IsNodeNeedMinimizeWithReason(const sptr<WindowNode>& node, MinimizeReason reason)
128{
129    if (node == nullptr) {
130        WLOGFE("[Minimize] node is nullptr");
131        return false;
132    }
133    if (needMinimizeAppNodes_.find(reason) == needMinimizeAppNodes_.end()) {
134        WLOGFD("[Minimize] no need to minimize with id:%{public}u reason:%{public}u",
135            node->GetWindowId(), reason);
136        return false;
137    }
138    auto nodes = needMinimizeAppNodes_.at(reason);
139    if (std::find(nodes.begin(), nodes.end(), node) != nodes.end()) {
140        WLOGI("[Minimize] id:%{public}u need to minimize with reason:%{public}u",
141            node->GetWindowId(), reason);
142        return true;
143    }
144    return false;
145}
146
147bool MinimizeApp::EnableMinimize(MinimizeReason reason)
148{
149    bool isFromUser = IsFromUser(reason);
150    if (!isMinimizedByOtherWindow_ && !isFromUser) {
151        return false;
152    }
153    return true;
154}
155
156void MinimizeApp::ExecuteMinimizeTargetReasons(uint32_t reasons)
157{
158    std::lock_guard<std::recursive_mutex> lock(mutex_);
159    while (reasons) {
160        MinimizeReason reason = static_cast<MinimizeReason>(reasons & (~reasons + 1));
161        if (needMinimizeAppNodes_.find(reason) != needMinimizeAppNodes_.end()) {
162            WLOGI("[Minimize] ExecuteMinimizeTargetReason with size: %{public}zu, reason: %{public}u",
163                needMinimizeAppNodes_.at(reason).size(), reason);
164            bool isFromUser = IsFromUser(reason);
165            for (auto& node : needMinimizeAppNodes_.at(reason)) {
166                WindowInnerManager::GetInstance().MinimizeAbility(node, isFromUser);
167            }
168            needMinimizeAppNodes_.at(reason).clear();
169        }
170        reasons -= reason;
171    }
172}
173
174void MinimizeApp::SetMinimizedByOtherConfig(bool isMinimizedByOther)
175{
176    isMinimizedByOtherWindow_ = isMinimizedByOther;
177}
178} // Rosen
179} // OHOS
180