1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
ash / wm / session_state_animator_impl_unittest.cc [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wm/session_state_animator_impl.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/session_state_animator.h"
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "ui/aura/client/aura_constants.h"
namespace ash {
namespace {
bool ParentHasWindowWithId(const aura::Window* window, int id) {
return window->parent()->GetId() == id;
}
bool ContainersHaveWindowWithId(const aura::Window::Windows windows, int id) {
for (const aura::Window* window : windows) {
if (window->GetId() == id)
return true;
}
return false;
}
} // namespace
using SessionStateAnimatiorImplContainersTest = AshTestBase;
TEST_F(SessionStateAnimatiorImplContainersTest, ContainersHaveIdTest) {
aura::Window::Windows containers;
// Test ROOT_CONTAINER mask.
aura::Window* root_window = Shell::GetPrimaryRootWindow();
SessionStateAnimatorImpl::GetContainers(SessionStateAnimator::ROOT_CONTAINER,
&containers);
EXPECT_EQ(root_window, containers[0]);
containers.clear();
SessionStateAnimatorImpl::GetContainers(SessionStateAnimator::WALLPAPER,
&containers);
EXPECT_TRUE(ContainersHaveWindowWithId(containers,
kShellWindowId_WallpaperContainer));
containers.clear();
// Check for shelf.
SessionStateAnimatorImpl::GetContainers(SessionStateAnimator::SHELF,
&containers);
EXPECT_TRUE(
ContainersHaveWindowWithId(containers, kShellWindowId_ShelfContainer));
containers.clear();
SessionStateAnimatorImpl::GetContainers(
SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, &containers);
EXPECT_TRUE(ParentHasWindowWithId(
containers[0], kShellWindowId_NonLockScreenContainersContainer));
// Verify the containers inside `NON_LOCK_SCREEN_CONTAINERS` be animated.
auto iter = std::find(containers.begin(), containers.end(),
desks_util::GetActiveDeskContainerForRoot(root_window));
EXPECT_TRUE(iter != containers.end());
for (const int id :
SessionStateAnimatorImpl::ContainersToAnimateInNonLockScreenContainer) {
iter = std::find(containers.begin(), containers.end(),
Shell::GetContainer(root_window, id));
EXPECT_TRUE(iter != containers.end());
}
containers.clear();
// Check for lock screen containers.
SessionStateAnimatorImpl::GetContainers(
SessionStateAnimator::LOCK_SCREEN_WALLPAPER, &containers);
EXPECT_TRUE(ContainersHaveWindowWithId(
containers, kShellWindowId_LockScreenWallpaperContainer));
containers.clear();
// Check for the lock screen containers container.
SessionStateAnimatorImpl::GetContainers(
SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS, &containers);
EXPECT_TRUE(ContainersHaveWindowWithId(
containers, kShellWindowId_LockScreenRelatedContainersContainer));
// Empty mask should clear the container.
SessionStateAnimatorImpl::GetContainers(0, &containers);
EXPECT_TRUE(containers.empty());
}
// Test that SessionStateAnimatorImpl invokes the callback only once on
// multi-display env, where it needs to run multiple animations on multiple
// containers. See http://crbug.com/712422 for details.
TEST_F(SessionStateAnimatiorImplContainersTest,
AnimationCallbackOnMultiDisplay) {
UpdateDisplay("300x200,500x400");
int callback_count = 0;
SessionStateAnimatorImpl animator;
animator.StartAnimationWithCallback(
SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
SessionStateAnimator::ANIMATION_LIFT,
SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE,
base::BindOnce([](int* count) { ++(*count); }, &callback_count));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, callback_count);
}
// Tests that AnimationSequence is not released prematurely because
// LayerCopyAnimator aborts animations due to display size change.
TEST_F(SessionStateAnimatiorImplContainersTest,
AnimationSequenceAndLayerCopyAnimator) {
UpdateDisplay("300x200,500x400");
base::RunLoop().RunUntilIdle();
// Create windows in containers of all displays so that the containers will
// be animated.
auto window_1 = CreateTestWindow(gfx::Rect(0, 0, 30, 20));
auto window_2 = CreateTestWindow(gfx::Rect(600, 0, 30, 20));
SessionStateAnimatorImpl animator;
// Creates LayerCopyAnimator on containers.
animator.StartAnimation(SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
SessionStateAnimator::ANIMATION_COPY_LAYER,
SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
// Simulate display changes that cause LayerCopyAnimators of first part of
// containers list to fail.
UpdateDisplay("600x500,500x400");
base::RunLoop animation_wait_loop;
auto animation_ended = [&](bool) { animation_wait_loop.Quit(); };
// Start a ANIMATION_DROP sequence.
SessionStateAnimator::AnimationSequence* animation_sequence =
animator.BeginAnimationSequence(
base::BindLambdaForTesting(animation_ended));
animation_sequence->StartAnimation(
SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
SessionStateAnimator::ANIMATION_DROP,
SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
animation_sequence->EndSequence();
// Wait for `animation_ended` to be called.
animation_wait_loop.Run();
// No crash or use-after-free should happen.
}
} // namespace ash