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#include <gtest/gtest.h>
16#include <transaction/rs_transaction.h>
17#include <ui/rs_surface_node.h>
18#include "display_test_utils.h"
19#include "display.h"
20#include "display_manager_proxy.h"
21#include "screen.h"
22#include "surface_draw.h"
23#include "wm_common.h"
24#include "wm_common_inner.h"
25#include "window.h"
26#include "window_option.h"
27#include "window_manager_hilog.h"
28#include "display_manager_agent_controller.h"
29
30using namespace testing;
31using namespace testing::ext;
32
33namespace OHOS::Rosen {
34namespace  {
35constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "DisplayManagerTest"};
36const int WAIT_FOR_SYNC_US = 1;  // 1s
37}
38
39class DisplayChangeEventListener : public DisplayManager::IDisplayListener {
40public:
41    virtual void OnCreate(DisplayId displayId) {}
42
43    virtual void OnDestroy(DisplayId displayId) {}
44
45    virtual void OnChange(DisplayId displayId) {}
46};
47
48class DisplayManagerTest : public testing::Test {
49public:
50    static void SetUpTestCase();
51    static void TearDownTestCase();
52    virtual void SetUp() override;
53    virtual void TearDown() override;
54
55    sptr<Window> CreateWindow(std::string name, WindowMode mode, Rect rect, uint32_t color = 0xff000000);
56    bool DrawWindowColor(const sptr<Window>& window, uint32_t color, int32_t width, int32_t height);
57    static inline DisplayId displayId_;
58    static inline int32_t displayWidth_;
59    static inline int32_t displayHeight_;
60};
61
62void DisplayManagerTest::SetUpTestCase()
63{
64    displayId_ = DisplayManager::GetInstance().GetDefaultDisplayId();
65    sptr<Display> display = DisplayManager::GetInstance().GetDefaultDisplay();
66    if (display == nullptr) {
67        return;
68    }
69    displayWidth_ = display->GetWidth();
70    displayHeight_ = display->GetHeight();
71}
72
73void DisplayManagerTest::TearDownTestCase()
74{
75}
76
77void DisplayManagerTest::SetUp()
78{
79}
80
81void DisplayManagerTest::TearDown()
82{
83}
84
85sptr<Window> DisplayManagerTest::CreateWindow(std::string name,
86    WindowMode mode, Rect rect, uint32_t color)
87{
88    sptr<WindowOption> option = new WindowOption();
89    option->SetDisplayId(displayId_);
90    option->SetWindowType(WindowType::WINDOW_TYPE_APP_MAIN_WINDOW);
91    int32_t width = 0;
92    int32_t height = 0;
93    if (mode != WindowMode::WINDOW_MODE_FULLSCREEN) {
94        option->SetWindowRect(rect);
95    } else {
96        width = displayWidth_;
97        height = displayHeight_;
98    }
99    option->SetWindowMode(mode);
100    option->SetWindowName(name);
101    sptr<Window> window = Window::Create(option->GetWindowName(), option);
102    if (window == nullptr) {
103        return nullptr;
104    }
105    window->AddWindowFlag(WindowFlag::WINDOW_FLAG_SHOW_WHEN_LOCKED);
106    window->Show();
107    sleep(WAIT_FOR_SYNC_US); // wait for rect updated
108    width = window->GetRect().width_;
109    height = window->GetRect().height_;
110    DrawWindowColor(window, color, width, height); // 0x66000000 color_black
111    RSTransaction::FlushImplicitTransaction();
112    return window;
113}
114
115bool DisplayManagerTest::DrawWindowColor(const sptr<Window>& window, uint32_t color, int32_t width, int32_t height)
116{
117    auto surfaceNode = window->GetSurfaceNode();
118    if (surfaceNode == nullptr) {
119        WLOGFE("Failed to GetSurfaceNode!");
120        return false;
121    }
122    SurfaceDraw::DrawColor(surfaceNode, width, height, color);
123    surfaceNode->SetAbilityBGAlpha(255); // 255 is alpha
124    return true;
125}
126
127namespace {
128/**
129 * @tc.name: HasPrivateWindow
130 * @tc.desc: Check whether there is a private window in the current display
131 * @tc.type: FUNC
132 * @tc.require issueI5HF6V
133 */
134HWTEST_F(DisplayManagerTest, HasPrivateWindow, Function | SmallTest | Level2)
135{
136    sptr<Window> window = CreateWindow("test", WindowMode::WINDOW_MODE_FULLSCREEN, Rect {0, 0, 0, 0});
137    if (window == nullptr) {
138        return;
139    }
140    ASSERT_NE(nullptr, window);
141    window->SetPrivacyMode(true);
142    sleep(WAIT_FOR_SYNC_US);
143    bool hasPrivateWindow = false;
144    DisplayId id = DisplayManager::GetInstance().GetDefaultDisplayId();
145    DisplayManager::GetInstance().HasPrivateWindow(id, hasPrivateWindow);
146
147    window->SetPrivacyMode(false);
148    sleep(WAIT_FOR_SYNC_US);
149    DisplayManager::GetInstance().HasPrivateWindow(id, hasPrivateWindow);
150    window->Destroy();
151    ASSERT_TRUE(!hasPrivateWindow);
152}
153
154/**
155 * @tc.name: HasPrivateWindowCovered
156 * @tc.desc: The private window is covered
157 * @tc.type: FUNC
158 * @tc.require issueI5HF6V
159 */
160HWTEST_F(DisplayManagerTest, HasPrivateWindowCovered, Function | SmallTest | Level2)
161{
162    auto displayWidth = DisplayManagerTest::displayWidth_;
163    auto displayHeight = DisplayManagerTest::displayHeight_;
164
165    sptr<Window> window1 = CreateWindow("test", WindowMode::WINDOW_MODE_FULLSCREEN, Rect {0, 0, 0, 0});
166    if (window1 == nullptr) {
167        return;
168    }
169    ASSERT_NE(nullptr, window1);
170    // 10:rect.posX_, 120:rect.posY_, 650:rect.width, 500:rect.height
171    sptr<Window> window2 = CreateWindow("private", WindowMode::WINDOW_MODE_FLOATING,
172                                        Rect{0, 0, 300, 300}, 0xffff0000);
173    ASSERT_NE(nullptr, window2);
174    window2->SetPrivacyMode(true);
175    // The window shadows is too large to cover. so, set a special position for cover window easily.
176    sleep(WAIT_FOR_SYNC_US);
177    window2->MoveTo(displayWidth * 0.53, displayHeight * 0.66);
178    sleep(WAIT_FOR_SYNC_US);
179
180    // 10:rect.posX_, 110:rect.posY_, 650:rect.width, 500:rect.height
181    sptr<Window> window3 = CreateWindow("covered", WindowMode::WINDOW_MODE_FLOATING,
182                                        Rect{0, 0, displayWidth, displayHeight}, 0xff00ff00);
183    ASSERT_NE(nullptr, window3);
184    sleep(WAIT_FOR_SYNC_US);
185    window3->MoveTo(45, 115);
186    sleep(WAIT_FOR_SYNC_US);
187
188    bool hasPrivateWindow = false;
189    DisplayId id = DisplayManager::GetInstance().GetDefaultDisplayId();
190    DisplayManager::GetInstance().HasPrivateWindow(id, hasPrivateWindow);
191    window1->Destroy();
192    window2->Destroy();
193    window3->Destroy();
194    if (!hasPrivateWindow) {
195        ASSERT_TRUE(!hasPrivateWindow);
196    }
197}
198
199/**
200 * @tc.name: HasPrivateWindowCovered01
201 * @tc.desc: The private window is partially covered
202 * @tc.type: FUNC
203 * @tc.require issueI5HF6V
204 */
205HWTEST_F(DisplayManagerTest, HasPrivateWindowCovered01, Function | SmallTest | Level2)
206{
207    sptr<Window> window1 = CreateWindow("test", WindowMode::WINDOW_MODE_FULLSCREEN, Rect{0, 0, 0, 0});
208
209    // 10:rect.posX_, 120:rect.posY_, 650:rect.width, 500:rect.height
210    if (window1 == nullptr)
211    {
212        return;
213    }
214    ASSERT_NE(nullptr, window1);
215    sptr<Window> window2 = CreateWindow("private", WindowMode::WINDOW_MODE_FLOATING,
216                                        Rect{10, 120, 650, 500}, 0xffff0000);
217    ASSERT_NE(nullptr, window2);
218    window2->SetPrivacyMode(true);
219    // 5:rect.posX_, 110:rect.posY_, 650:rect.width, 500:rect.height
220    sptr<Window> window3 = CreateWindow("covered", WindowMode::WINDOW_MODE_FLOATING,
221                                        Rect{5, 110, 650, 500}, 0xff00ff00);
222    ASSERT_NE(nullptr, window3);
223
224    sleep(WAIT_FOR_SYNC_US);
225    bool hasPrivateWindow = false;
226    DisplayId id = DisplayManager::GetInstance().GetDefaultDisplayId();
227    DisplayManager::GetInstance().HasPrivateWindow(id, hasPrivateWindow);
228    window1->Destroy();
229    window2->Destroy();
230    window3->Destroy();
231    if (hasPrivateWindow)
232    {
233        ASSERT_TRUE(hasPrivateWindow);
234    }
235}
236
237/**
238 * @tc.name: HasPrivateWindowCovered02
239 * @tc.desc: The private window is covered
240 * @tc.type: FUNC
241 * @tc.require issueI5HF6V
242 */
243HWTEST_F(DisplayManagerTest, HasPrivateWindowCovered02, Function | SmallTest | Level2)
244{
245    auto displayWidth = DisplayManagerTest::displayWidth_;
246    auto displayHeight = DisplayManagerTest::displayHeight_;
247
248    sptr<Window> window1 = CreateWindow("test", WindowMode::WINDOW_MODE_FULLSCREEN, Rect {0, 0, 0, 0});
249    if (window1 == nullptr) {
250        return;
251    }
252    ASSERT_NE(nullptr, window1);
253    // 10:rect.posX_, 120:rect.posY_, 650:rect.width, 500:rect.height
254    sptr<Window> window2 = CreateWindow("private", WindowMode::WINDOW_MODE_FLOATING,
255                                        Rect {0, 0, 300, 300}, 0xffff0000);
256    ASSERT_NE(nullptr, window2);
257    window2->SetPrivacyMode(true);
258    // The window shadows is too large to cover. so, set a special position for cover window easily.
259    sleep(WAIT_FOR_SYNC_US);
260    window2->MoveTo(displayWidth * 0.53, displayHeight * 0.66);
261    sleep(WAIT_FOR_SYNC_US);
262
263    // 5:rect.posX_, 110:rect.posY_, 655:rect.width, 500:rect.height
264    sptr<Window> window3 = CreateWindow("covered1", WindowMode::WINDOW_MODE_FLOATING,
265                                        Rect { 0, 0, displayWidth, displayHeight / 2}, 0xff00ff00);
266    ASSERT_NE(nullptr, window3);
267    sleep(WAIT_FOR_SYNC_US);
268    window3->MoveTo(45, 115);
269    sleep(WAIT_FOR_SYNC_US);
270
271    // 5:rect.posX_, 300:rect.posY_, 655:rect.width, 500:rect.height
272    sptr<Window> window4 = CreateWindow("covered2", WindowMode::WINDOW_MODE_FLOATING,
273                                        Rect { 0, 0, displayWidth, displayHeight / 2 + 200 }, 0xff00ff00);
274    ASSERT_NE(nullptr, window4);
275    window4->MoveTo(45, displayHeight / 2 - 95);
276
277    sleep(WAIT_FOR_SYNC_US);
278    bool hasPrivateWindow = false;
279    DisplayId id = DisplayManager::GetInstance().GetDefaultDisplayId();
280    DisplayManager::GetInstance().HasPrivateWindow(id, hasPrivateWindow);
281    window1->Destroy();
282    window2->Destroy();
283    window3->Destroy();
284    window4->Destroy();
285    if (!hasPrivateWindow) {
286        ASSERT_TRUE(!hasPrivateWindow);
287    }
288}
289
290/**
291 * @tc.name: HasPrivateWindowCovered03
292 * @tc.desc: The private window is partially covered
293 * @tc.type: FUNC
294 * @tc.require issueI5HF6V
295 */
296HWTEST_F(DisplayManagerTest, HasPrivateWindowCovered03, Function | SmallTest | Level2)
297{
298    sptr<Window> window1 = CreateWindow("test", WindowMode::WINDOW_MODE_FULLSCREEN, Rect {0, 0, 0, 0});
299
300    if (window1 == nullptr) {
301        return;
302    }
303    ASSERT_NE(nullptr, window1);
304    // 10:rect.posX_, 120:rect.pos_Y, rect.width_:650, rect.height_:700
305    sptr<Window> window2 = CreateWindow("private", WindowMode::WINDOW_MODE_FLOATING,
306                                        Rect{10, 120, 650, 700}, 0xffff0000);
307    ASSERT_NE(nullptr, window2);
308    window2->SetPrivacyMode(true);
309    // 5:rect.posX_, 110:rect.pos_Y, rect.width_:655, rect.height_:500
310    sptr<Window> window3 = CreateWindow("covered1", WindowMode::WINDOW_MODE_FLOATING,
311                                        Rect{5, 110, 655, 500}, 0xff00ff00);
312    ASSERT_NE(nullptr, window3);
313    // 5:rect.posX_, 700:rect.pos_Y, rect.width_:655, rect.height_:500
314    sptr<Window> window4 = CreateWindow("covered2", WindowMode::WINDOW_MODE_FLOATING,
315                                        Rect{5, 700, 655, 500}, 0xff00ff00);
316    ASSERT_NE(nullptr, window4);
317
318    sleep(WAIT_FOR_SYNC_US);
319    bool hasPrivateWindow = false;
320    DisplayId id = DisplayManager::GetInstance().GetDefaultDisplayId();
321    DisplayManager::GetInstance().HasPrivateWindow(id, hasPrivateWindow);
322    window1->Destroy();
323    window2->Destroy();
324    window3->Destroy();
325    window4->Destroy();
326    if (hasPrivateWindow) {
327        ASSERT_TRUE(hasPrivateWindow);
328    }
329}
330
331/**
332 * @tc.name: HasPrivateWindowSkipSnapShot
333 * @tc.desc: set snap shot skip
334 * @tc.type: FUNC
335 * @tc.require issueI5HF6V
336 */
337HWTEST_F(DisplayManagerTest, HasPrivateWindowSkipSnapShot, Function | SmallTest | Level2)
338{
339    sptr<Window> window1 = CreateWindow("test", WindowMode::WINDOW_MODE_FULLSCREEN, Rect {0, 0, 0, 0});
340    if (window1 == nullptr) {
341        return;
342    }
343    ASSERT_NE(nullptr, window1);
344    // 10:rect.posX_, 120:rect.posY_, 650:rect.width, 500:rect.height
345    sptr<Window> window2 = CreateWindow("private", WindowMode::WINDOW_MODE_FLOATING,
346        Rect {10, 120, 650, 500}, 0xffff0000);
347    ASSERT_NE(nullptr, window2);
348    window2->SetSnapshotSkip(true);
349    sleep(WAIT_FOR_SYNC_US);
350    bool hasPrivateWindow = false;
351    DisplayId id = DisplayManager::GetInstance().GetDefaultDisplayId();
352    DisplayManager::GetInstance().HasPrivateWindow(id, hasPrivateWindow);
353    window1->Destroy();
354    window2->Destroy();
355    if (hasPrivateWindow) {
356        ASSERT_TRUE(hasPrivateWindow);
357    }
358}
359
360/**
361 * @tc.name: AddSurfaceNodeToDisplay | RemoveSurfaceNodeFromDisplay
362 * @tc.desc: add/remove surfaceNode to/from display
363 * @tc.type: FUNC
364 */
365HWTEST_F(DisplayManagerTest, AddAndRemoveSurfaceNode, Function | SmallTest | Level2)
366{
367    RSSurfaceNodeConfig config;
368    config.SurfaceNodeName = "TestSurfaceNode";
369    auto surfaceNode = RSSurfaceNode::Create(config);
370    DisplayId id = DisplayManager::GetInstance().GetDefaultDisplayId();
371    ASSERT_EQ(DMError::DM_OK, DisplayManager::GetInstance().AddSurfaceNodeToDisplay(id, surfaceNode));
372    sleep(2);
373    ASSERT_EQ(DMError::DM_OK, DisplayManager::GetInstance().RemoveSurfaceNodeFromDisplay(id, surfaceNode));
374}
375
376/**
377 * @tc.name: AddSurfaceNodeToDisplay | RemoveSurfaceNodeFromDisplay
378 * @tc.desc: add/remove surfaceNode to/from display
379 * @tc.type: FUNC
380 */
381HWTEST_F(DisplayManagerTest, SetVirtualScreenSecurityExemption, Function | SmallTest | Level2)
382{
383    ScreenId id = 0;
384    uint32_t pid = 0;
385    std::vector<uint64_t> windowList;
386    auto ret = DisplayManager::GetInstance().SetVirtualScreenSecurityExemption(id, pid, windowList);
387    ASSERT_NE(DMError::DM_OK, ret); // not virtual screen for id 0
388    sleep(2);
389}
390
391}
392} // namespace OHOS::Rosen
393