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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
ash / shelf / swipe_home_to_overview_controller.cc [blame]
// Copyright 2019 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/shelf/swipe_home_to_overview_controller.h"
#include <algorithm>
#include <optional>
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/constants/ash_features.h"
#include "ash/controls/contextual_tooltip.h"
#include "ash/public/cpp/app_list/app_list_config.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/drag_window_from_shelf_controller.h"
#include "ash/shelf/shelf_metrics.h"
#include "ash/shell.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_session.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/default_tick_clock.h"
#include "ui/compositor/layer_animation_element.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/animation/tween.h"
namespace ash {
namespace {
// The target/min home launcher view scale.
constexpr float kTargetHomeScale = 0.92f;
// The home UI will be scaled down towards center of the screen as drag location
// moves upwards. The target threshold for scaling is extended above the actual
// threshold for transition so the UI keeps changing even when the gesture goes
// over the threshold. This is the target home screen scaling threshold in terms
// of ratio of the display height.
constexpr float kHomeScalingThresholdDisplayHeightRatio = 0.5f;
// The amount of time the drag has to remain bellow velocity threshold before
// the transition to the overview starts.
constexpr base::TimeDelta kOverviewTransitionDelay = base::Milliseconds(150);
// The duration of transition from the home screen current scaled state to the
// initial (unscaled) state when the gesture is canceled.
constexpr base::TimeDelta kGestureCancelationDuration = base::Milliseconds(350);
// The duration of transition from the home screen current scaled state to the
// initial (unscaled) state when the gesture is canceled due to a back gesture.
constexpr base::TimeDelta kGestureCancelationForBackDuration =
base::Milliseconds(250);
void UpdateHomeAnimationForGestureCancel(
bool going_back,
ui::ScopedLayerAnimationSettings* settings) {
settings->SetTransitionDuration(going_back
? kGestureCancelationForBackDuration
: kGestureCancelationDuration);
settings->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
settings->SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
}
} // namespace
SwipeHomeToOverviewController::SwipeHomeToOverviewController(int64_t display_id)
: SwipeHomeToOverviewController(display_id,
base::DefaultTickClock::GetInstance()) {}
SwipeHomeToOverviewController::SwipeHomeToOverviewController(
int64_t display_id,
const base::TickClock* tick_clock)
: display_id_(display_id), overview_transition_timer_(tick_clock) {}
SwipeHomeToOverviewController::~SwipeHomeToOverviewController() {
CancelDrag();
}
void SwipeHomeToOverviewController::Drag(const gfx::PointF& location_in_screen,
float scroll_x,
float scroll_y) {
if (state_ == State::kFinished)
return;
display::Display display;
if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id_,
&display)) {
CancelDrag();
return;
}
const int shelf_top =
display.bounds().bottom() - ShelfConfig::Get()->shelf_size();
if (state_ == State::kInitial) {
// Do not start drag until the drag goes above the shelf.
if (location_in_screen.y() > shelf_top)
return;
overview_transition_threshold_y_ =
shelf_top - kVerticalThresholdForOverviewTransition;
scaling_threshold_y_ =
display.bounds().y() +
display.bounds().height() * kHomeScalingThresholdDisplayHeightRatio;
state_ = State::kTrackingDrag;
} else {
if (location_in_screen.y() <= overview_transition_threshold_y_ &&
std::abs(scroll_x) + std::abs(scroll_y) <= kMovementVelocityThreshold) {
ScheduleFinalizeDragAndShowOverview();
} else {
overview_transition_timer_.Stop();
}
}
// Update the home screen scale to match progress during the drag.
// Use extended threshold as the projected final transition position - UI
// changing even after the user gets over the threshold should make the user
// more likely to keep dragging up when they get really close to the threshold
// for transition to overview (and reduce false negatives for detecting
// transition to overview).
const float distance = location_in_screen.y() - scaling_threshold_y_;
const float target_distance = overview_transition_threshold_y_ -
scaling_threshold_y_ +
kVerticalThresholdForOverviewTransition;
const float progress = gfx::Tween::CalculateValue(
gfx::Tween::FAST_OUT_SLOW_IN,
std::clamp(1.f - distance / target_distance, 0.0f, 1.0f));
float scale = gfx::Tween::FloatValueBetween(progress, 1.0f, kTargetHomeScale);
Shell::Get()->app_list_controller()->UpdateScaleAndOpacityForHomeLauncher(
scale, 1.0f /*opacity*/, std::nullopt /*animation_info*/,
base::NullCallback());
}
void SwipeHomeToOverviewController::EndDrag(
const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) {
if (state_ != State::kTrackingDrag) {
state_ = State::kFinished;
return;
}
// Upward swipe should return to the home screen's initial state.
const bool go_back =
velocity_y &&
*velocity_y <
-DragWindowFromShelfController::kVelocityToHomeScreenThreshold;
// Overview is triggered by |overview_transition_timer_|. If EndDrag()
// is called before the timer fires, the result of the gesture should be
// staying on the home screen.
FinalizeDragAndStayOnHomeScreen(go_back);
}
void SwipeHomeToOverviewController::CancelDrag() {
if (state_ != State::kTrackingDrag) {
state_ = State::kFinished;
return;
}
FinalizeDragAndStayOnHomeScreen(/*go_back=*/false);
}
void SwipeHomeToOverviewController::ScheduleFinalizeDragAndShowOverview() {
if (overview_transition_timer_.IsRunning())
return;
overview_transition_timer_.Start(
FROM_HERE, kOverviewTransitionDelay,
base::BindOnce(
&SwipeHomeToOverviewController::FinalizeDragAndShowOverview,
base::Unretained(this)));
}
void SwipeHomeToOverviewController::FinalizeDragAndShowOverview() {
state_ = State::kFinished;
overview_transition_threshold_y_ = 0;
if (features::IsHideShelfControlsInTabletModeEnabled()) {
contextual_tooltip::HandleGesturePerformed(
Shell::Get()->session_controller()->GetActivePrefService(),
contextual_tooltip::TooltipType::kHomeToOverview);
}
UMA_HISTOGRAM_ENUMERATION(kEnterOverviewHistogramName,
EnterOverviewFromHomeLauncher::kOverview);
// NOTE: No need to update the home launcher opacity and scale here - the
// AppListControllerImpl will update the home launcher state when it detects
// that the overview is starting.
Shell::Get()->overview_controller()->StartOverview(
OverviewStartAction::kExitHomeLauncher);
}
void SwipeHomeToOverviewController::FinalizeDragAndStayOnHomeScreen(
bool go_back) {
overview_transition_timer_.Stop();
overview_transition_threshold_y_ = 0;
state_ = State::kFinished;
// App list controller may get destroyed before shelf during shutdown.
auto* const app_list_controller = Shell::Get()->app_list_controller();
if (!app_list_controller) {
return;
}
if (go_back) {
app_list_controller->Back();
UMA_HISTOGRAM_ENUMERATION(kEnterOverviewHistogramName,
EnterOverviewFromHomeLauncher::kBack);
} else {
UMA_HISTOGRAM_ENUMERATION(kEnterOverviewHistogramName,
EnterOverviewFromHomeLauncher::kCanceled);
}
// Make sure the home launcher scale and opacity return to the initial state.
// Note that this is needed even if the gesture ended up in a fling, as early
// gesture handling might have updated the launcher scale.
app_list_controller->UpdateScaleAndOpacityForHomeLauncher(
1.0f /*scale*/, 1.0f /*opacity*/, std::nullopt /*animation_info*/,
base::BindRepeating(&UpdateHomeAnimationForGestureCancel, go_back));
}
} // namespace ash