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
158
159
160
161
162
163
164
165
166
167
168
169
170
ash / wm / desks / desk_animation_base.h [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_WM_DESKS_DESK_ANIMATION_BASE_H_
#define ASH_WM_DESKS_DESK_ANIMATION_BASE_H_
#include "ash/ash_export.h"
#include "ash/public/cpp/metrics_util.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desks_histogram_enums.h"
#include "ash/wm/desks/root_window_desk_switch_animator.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "ui/compositor/compositor_metrics_tracker.h"
namespace ash {
class DesksController;
// An abstract class that handles the shared operations need to be performed
// when doing an animation that causes a desk switch animation. Subclasses
// such as DeskActivationAnimation and DeskRemovalAnimation implement the
// abstract interface of this class to handle the unique operations specific to
// each animation type.
class ASH_EXPORT DeskAnimationBase
: public RootWindowDeskSwitchAnimator::Delegate {
public:
DeskAnimationBase(DesksController* controller,
int ending_desk_index,
bool is_continuous_gesture_animation);
DeskAnimationBase(const DeskAnimationBase&) = delete;
DeskAnimationBase& operator=(const DeskAnimationBase&) = delete;
~DeskAnimationBase() override;
int ending_desk_index() const { return ending_desk_index_; }
int visible_desk_changes() const { return visible_desk_changes_; }
// Launches the animation. This should be done once all animators
// are created and added to `desk_switch_animators_`. This is to avoid any
// potential race conditions that might happen if one animator finished phase
// (1) of the animation while other animators are still being constructed.
void Launch();
// Replaces a current animation with an animation to an adjacent desk. By
// default returns false as most animations do not support replacing.
virtual bool Replace(bool moving_left, DesksSwitchSource source);
// Updates a current animation by shifting its animating layer.
// |scroll_delta_x| is the amount of scroll change since the last scroll
// update event. Returns false if the animation does not support updating.
virtual bool UpdateSwipeAnimation(float scroll_delta_x);
// Ends a current animation, animating to a desk determined by the
// implementation. Returns false if the animation does not support ending.
virtual bool EndSwipeAnimation();
// Returns true if entering/exiting overview during the animation is allowed.
virtual bool CanEnterOverview() const;
virtual bool CanEndOverview() const;
// RootWindowDeskSwitchAnimator::Delegate:
void OnStartingDeskScreenshotTaken(int ending_desk_index) override;
void OnEndingDeskScreenshotTaken() override;
void OnDeskSwitchAnimationFinished() override;
void set_finished_callback(base::OnceClosure finished_callback) {
DCHECK(finished_callback_.is_null());
finished_callback_ = std::move(finished_callback);
}
void set_skip_notify_controller_on_animation_finished_for_testing(bool val) {
skip_notify_controller_on_animation_finished_for_testing_ = val;
}
RootWindowDeskSwitchAnimator* GetDeskSwitchAnimatorAtIndexForTesting(
size_t index) const;
protected:
// This will set `is_overview_toggle_allowed_` before and after calling
// `ActivateDeskInternal()`, allowing exiting/entering overview during the
// animation.
void ActivateDeskDuringAnimation(const Desk* desk,
bool update_window_activation);
// Immediately switches to the target desk and notifies the desk controller
// that the animation is done, which will end up deleting `this`.
void ActivateTargetDeskWithoutAnimation();
// Returns true if any of the animators have failed, for any reason. In this
// case, we will abort what we're doing and switch to the target desk without
// animation.
bool AnimatorFailed() const;
// Abstract functions that can be overridden by child classes to do different
// things when phase (1), and phase (3) completes. Note that
// `OnDeskSwitchAnimationFinishedInternal()` will be called before the desks
// screenshot layers, stored in `desk_switch_animators_`, are destroyed.
virtual void OnStartingDeskScreenshotTakenInternal(int ending_desk_index) = 0;
virtual void OnDeskSwitchAnimationFinishedInternal() = 0;
// Since performance here matters, we have to use the UMA histograms macros to
// report the histograms, but each macro use has to be associated with exactly
// one histogram name. These functions allow subclasses to return callbacks
// that report each histogram using the macro with their desired name.
using LatencyReportCallback =
base::OnceCallback<void(const base::TimeDelta& latency)>;
virtual LatencyReportCallback GetLatencyReportCallback() const = 0;
virtual metrics_util::ReportCallback GetSmoothnessReportCallback() const = 0;
const raw_ptr<DesksController> controller_;
// An animator object per each root. Once all the animations are complete,
// this list is cleared.
std::vector<std::unique_ptr<RootWindowDeskSwitchAnimator>>
desk_switch_animators_;
// The index of the desk that will be active after this animation ends.
int ending_desk_index_;
// True if this animation is a continuous gesture animation. Update and End
// only work when this is true, and we do not start the animation when
// OnEndingDeskScreenshotTaken is called.
const bool is_continuous_gesture_animation_;
// Used when the animation is a continuous gesture animation. True when
// `EndSwipeAnimation()` has been called and a fast swipe was detected, and
// reset to false if `Replace()` has been called. A fast swipe is one where
// the user starts and ends the swipe gesture within half a second. If this is
// false, we do not start the animation when `OnEndingDeskScreenshotTaken` is
// called.
bool did_continuous_gesture_end_fast_ = false;
// Used for metrics collection to track how many desks changes a user has seen
// during the animation. This is different from the number of desk activations
// as the user may switch desks but not activate it if the desk already has a
// screenshot taken. This will only change for an activation animation, not a
// remove animation.
int visible_desk_changes_ = 0;
// Used for allowing us to enter or exit overview during a desk animation. If
// there is an ongoing desk animation, we want to prevent unwanted exit or
// enter overview toggling so that we don't end up in a strange or unexpected
// state. Toggling overview is only allowed when we are doing an internal desk
// activation, where we manually set the overview states of the old active
// desk and the new active desk.
bool is_overview_toggle_allowed_ = false;
// Used for the Ash.Desks.AnimationLatency.* histograms. Null if no animation
// is being prepared. In a continuous desk animation, the latency is reported
// only for the first desk switch, and `launch_time_` is null thereafter.
base::TimeTicks launch_time_;
// ThroughputTracker used for measuring this animation smoothness.
std::optional<ui::ThroughputTracker> throughput_tracker_;
// If true, do not notify |controller_| when
// OnDeskSwitchAnimationFinished() is called. This class and
// DeskController are tied together in production code, but may not be in a
// test scenario.
bool skip_notify_controller_on_animation_finished_for_testing_ = false;
// Callback for when the animation is finished.
base::OnceClosure finished_callback_;
};
} // namespace ash
#endif // ASH_WM_DESKS_DESK_ANIMATION_BASE_H_