drag_window_from_shelf_controller.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/shelf/drag_window_from_shelf_controller.h"
  5. #include "ash/app_list/app_list_controller_impl.h"
  6. #include "ash/display/screen_orientation_controller.h"
  7. #include "ash/public/cpp/shelf_config.h"
  8. #include "ash/public/cpp/window_backdrop.h"
  9. #include "ash/public/cpp/window_properties.h"
  10. #include "ash/root_window_controller.h"
  11. #include "ash/scoped_animation_disabler.h"
  12. #include "ash/screen_util.h"
  13. #include "ash/shelf/hotseat_widget.h"
  14. #include "ash/shelf/shelf.h"
  15. #include "ash/shelf/window_scale_animation.h"
  16. #include "ash/shell.h"
  17. #include "ash/wallpaper/wallpaper_constants.h"
  18. #include "ash/wallpaper/wallpaper_view.h"
  19. #include "ash/wallpaper/wallpaper_widget_controller.h"
  20. #include "ash/wm/mru_window_tracker.h"
  21. #include "ash/wm/overview/overview_constants.h"
  22. #include "ash/wm/overview/overview_controller.h"
  23. #include "ash/wm/overview/overview_session.h"
  24. #include "ash/wm/overview/overview_utils.h"
  25. #include "ash/wm/splitview/split_view_controller.h"
  26. #include "ash/wm/splitview/split_view_drag_indicators.h"
  27. #include "ash/wm/splitview/split_view_utils.h"
  28. #include "ash/wm/window_properties.h"
  29. #include "ash/wm/window_state.h"
  30. #include "ash/wm/window_transient_descendant_iterator.h"
  31. #include "ash/wm/window_util.h"
  32. #include "base/bind.h"
  33. #include "base/callback_helpers.h"
  34. #include "base/cxx17_backports.h"
  35. #include "base/metrics/histogram_macros.h"
  36. #include "ui/aura/window_tree_host.h"
  37. #include "ui/base/hit_test.h"
  38. #include "ui/compositor/layer.h"
  39. #include "ui/compositor/layer_animation_observer.h"
  40. #include "ui/compositor/presentation_time_recorder.h"
  41. #include "ui/compositor/scoped_layer_animation_settings.h"
  42. #include "ui/display/screen.h"
  43. #include "ui/gfx/geometry/point_f.h"
  44. #include "ui/gfx/geometry/transform_util.h"
  45. #include "ui/wm/core/coordinate_conversion.h"
  46. #include "ui/wm/core/window_util.h"
  47. namespace ash {
  48. namespace {
  49. // The minimum window scale factor when dragging a window from shelf.
  50. constexpr float kMinimumWindowScaleDuringDragging = 0.3f;
  51. // The ratio in display height at which point the dragged window shrinks to its
  52. // minimum scale kMinimumWindowScaleDuringDragging.
  53. constexpr float kMinYDisplayHeightRatio = 0.125f;
  54. // Amount of time to wait to show overview after the user slows down or stops
  55. // window dragging.
  56. constexpr base::TimeDelta kShowOverviewTimeWhenDragSuspend =
  57. base::Milliseconds(40);
  58. // The scroll update threshold to restart the show overview timer.
  59. constexpr float kScrollUpdateOverviewThreshold = 2.f;
  60. // Presentation time histogram names.
  61. constexpr char kDragWindowFromShelfHistogram[] =
  62. "Ash.DragWindowFromShelf.PresentationTime";
  63. constexpr char kDragWindowFromShelfMaxLatencyHistogram[] =
  64. "Ash.DragWindowFromShelf.PresentationTime.MaxLatency";
  65. } // namespace
  66. // Hide all visible windows expect the dragged windows or the window showing in
  67. // splitview during dragging.
  68. class DragWindowFromShelfController::WindowsHider
  69. : public aura::WindowObserver {
  70. public:
  71. explicit WindowsHider(aura::Window* dragged_window)
  72. : dragged_window_(dragged_window) {
  73. std::vector<aura::Window*> windows =
  74. Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
  75. for (auto* window : windows) {
  76. if (window == dragged_window_)
  77. continue;
  78. if (::wm::HasTransientAncestor(window, dragged_window_))
  79. continue;
  80. if (!window->IsVisible())
  81. continue;
  82. if (SplitViewController::Get(window)->IsWindowInSplitView(window))
  83. continue;
  84. hidden_windows_.push_back(window);
  85. window->AddObserver(this);
  86. window->SetProperty(kHideDuringWindowDragging, true);
  87. }
  88. window_util::MinimizeAndHideWithoutAnimation(hidden_windows_);
  89. }
  90. WindowsHider(const WindowsHider&) = delete;
  91. WindowsHider& operator=(const WindowsHider&) = delete;
  92. ~WindowsHider() override {
  93. for (auto* window : hidden_windows_) {
  94. window->RemoveObserver(this);
  95. window->ClearProperty(kHideDuringWindowDragging);
  96. }
  97. hidden_windows_.clear();
  98. }
  99. void RestoreWindowsVisibility() {
  100. for (auto* window : hidden_windows_) {
  101. window->RemoveObserver(this);
  102. ScopedAnimationDisabler disabler(window);
  103. window->Show();
  104. window->ClearProperty(kHideDuringWindowDragging);
  105. }
  106. hidden_windows_.clear();
  107. }
  108. // Even though we explicitly minimize the windows, some (i.e. ARC apps)
  109. // minimize asynchronously so they may not be truly minimized after |this| is
  110. // constructed.
  111. bool WindowsMinimized() {
  112. return std::all_of(hidden_windows_.begin(), hidden_windows_.end(),
  113. [](const aura::Window* w) {
  114. return WindowState::Get(w)->IsMinimized();
  115. });
  116. }
  117. // aura::WindowObserver:
  118. void OnWindowDestroying(aura::Window* window) override {
  119. window->RemoveObserver(this);
  120. hidden_windows_.erase(
  121. std::find(hidden_windows_.begin(), hidden_windows_.end(), window));
  122. }
  123. private:
  124. aura::Window* dragged_window_;
  125. std::vector<aura::Window*> hidden_windows_;
  126. };
  127. // static
  128. float DragWindowFromShelfController::GetReturnToMaximizedThreshold() {
  129. return Shell::GetPrimaryRootWindowController()
  130. ->shelf()
  131. ->hotseat_widget()
  132. ->GetHotseatFullDragAmount();
  133. }
  134. DragWindowFromShelfController::DragWindowFromShelfController(
  135. aura::Window* window,
  136. const gfx::PointF& location_in_screen)
  137. : window_(window) {
  138. window_->AddObserver(this);
  139. OnDragStarted(location_in_screen);
  140. presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder(
  141. window_->GetHost()->compositor(), kDragWindowFromShelfHistogram,
  142. kDragWindowFromShelfMaxLatencyHistogram);
  143. }
  144. DragWindowFromShelfController::~DragWindowFromShelfController() {
  145. CancelDrag();
  146. if (window_)
  147. window_->RemoveObserver(this);
  148. }
  149. void DragWindowFromShelfController::Drag(const gfx::PointF& location_in_screen,
  150. float scroll_x,
  151. float scroll_y) {
  152. // |window_| might have been destroyed during dragging.
  153. if (!window_)
  154. return;
  155. if (!drag_started_)
  156. return;
  157. presentation_time_recorder_->RequestNext();
  158. UpdateDraggedWindow(location_in_screen);
  159. // Open overview if the window has been dragged far enough and the scroll
  160. // delta has decreased to kOpenOverviewThreshold. Wait until all windows are
  161. // minimized or they will not show up in overview.
  162. DCHECK(windows_hider_);
  163. OverviewController* overview_controller = Shell::Get()->overview_controller();
  164. if (std::abs(scroll_y) <= kOpenOverviewThreshold &&
  165. !overview_controller->InOverviewSession() &&
  166. windows_hider_->WindowsMinimized()) {
  167. overview_controller->StartOverview(
  168. OverviewStartAction::kDragWindowFromShelf,
  169. OverviewEnterExitType::kImmediateEnter);
  170. OnWindowDragStartedInOverview();
  171. }
  172. // If overview is active, update its splitview indicator during dragging if
  173. // splitview is allowed in current configuration.
  174. if (overview_controller->InOverviewSession()) {
  175. const SplitViewController::SnapPosition snap_position =
  176. GetSnapPosition(location_in_screen);
  177. const SplitViewDragIndicators::WindowDraggingState window_dragging_state =
  178. SplitViewDragIndicators::ComputeWindowDraggingState(
  179. /*is_dragging=*/true,
  180. SplitViewDragIndicators::WindowDraggingState::kFromShelf,
  181. snap_position);
  182. OverviewSession* overview_session = overview_controller->overview_session();
  183. overview_session->UpdateSplitViewDragIndicatorsWindowDraggingStates(
  184. Shell::GetPrimaryRootWindow(), window_dragging_state);
  185. overview_session->OnWindowDragContinued(window_, location_in_screen,
  186. window_dragging_state);
  187. if (snap_position != SplitViewController::NONE) {
  188. // If the dragged window is in snap preview area, make sure overview is
  189. // visible.
  190. ShowOverviewDuringOrAfterDrag();
  191. } else if (std::abs(scroll_x) > kShowOverviewThreshold ||
  192. std::abs(scroll_y) > kShowOverviewThreshold) {
  193. // If the dragging velocity is large enough, hide overview windows.
  194. show_overview_timer_.Stop();
  195. HideOverviewDuringDrag();
  196. } else if (!show_overview_timer_.IsRunning() ||
  197. std::abs(scroll_x) > kScrollUpdateOverviewThreshold ||
  198. std::abs(scroll_y) > kScrollUpdateOverviewThreshold) {
  199. // Otherwise start the |show_overview_timer_| to show and update
  200. // overview when the dragging slows down or stops. Note if the window is
  201. // still being dragged with scroll rate more than
  202. // kScrollUpdateOverviewThreshold, we restart the show overview timer.
  203. show_overview_timer_.Start(
  204. FROM_HERE, kShowOverviewTimeWhenDragSuspend, this,
  205. &DragWindowFromShelfController::ShowOverviewDuringOrAfterDrag);
  206. }
  207. }
  208. previous_location_in_screen_ = location_in_screen;
  209. }
  210. absl::optional<ShelfWindowDragResult> DragWindowFromShelfController::EndDrag(
  211. const gfx::PointF& location_in_screen,
  212. absl::optional<float> velocity_y) {
  213. if (!drag_started_)
  214. return absl::nullopt;
  215. UpdateDraggedWindow(location_in_screen);
  216. drag_started_ = false;
  217. previous_location_in_screen_ = location_in_screen;
  218. presentation_time_recorder_.reset();
  219. OverviewController* overview_controller = Shell::Get()->overview_controller();
  220. SplitViewController* split_view_controller =
  221. SplitViewController::Get(Shell::GetPrimaryRootWindow());
  222. const bool in_overview = overview_controller->InOverviewSession();
  223. const bool in_splitview = split_view_controller->InSplitViewMode();
  224. const bool drop_window_in_overview =
  225. ShouldDropWindowInOverview(location_in_screen, velocity_y);
  226. end_snap_position_ = GetSnapPositionOnDragEnd(location_in_screen, velocity_y);
  227. window_drag_result_ = absl::nullopt;
  228. if (ShouldGoToHomeScreen(location_in_screen, velocity_y)) {
  229. DCHECK(!in_splitview);
  230. if (in_overview) {
  231. overview_controller->EndOverview(OverviewEndAction::kDragWindowFromShelf,
  232. OverviewEnterExitType::kFadeOutExit);
  233. }
  234. window_drag_result_ = ShelfWindowDragResult::kGoToHomeScreen;
  235. } else if (ShouldRestoreToOriginalBounds(location_in_screen, velocity_y)) {
  236. window_drag_result_ = ShelfWindowDragResult::kRestoreToOriginalBounds;
  237. } else if (!in_overview) {
  238. // if overview is not active during the entire drag process, scale down the
  239. // dragged window to go to home screen.
  240. window_drag_result_ = ShelfWindowDragResult::kGoToHomeScreen;
  241. } else {
  242. if (drop_window_in_overview)
  243. window_drag_result_ = ShelfWindowDragResult::kGoToOverviewMode;
  244. else if (end_snap_position_ != SplitViewController::NONE)
  245. window_drag_result_ = ShelfWindowDragResult::kGoToSplitviewMode;
  246. // For window that may drop in overview or snap in split screen, restore its
  247. // original backdrop mode.
  248. WindowBackdrop::Get(window_)->RestoreBackdrop();
  249. }
  250. WindowState::Get(window_)->DeleteDragDetails();
  251. if (window_drag_result_.has_value()) {
  252. UMA_HISTOGRAM_ENUMERATION(kHandleDragWindowFromShelfHistogramName,
  253. *window_drag_result_);
  254. }
  255. return window_drag_result_;
  256. }
  257. void DragWindowFromShelfController::CancelDrag() {
  258. if (!drag_started_)
  259. return;
  260. UMA_HISTOGRAM_ENUMERATION(kHandleDragWindowFromShelfHistogramName,
  261. ShelfWindowDragResult::kDragCanceled);
  262. drag_started_ = false;
  263. presentation_time_recorder_.reset();
  264. // Reset the window's transform to identity transform.
  265. window_->SetTransform(gfx::Transform());
  266. WindowBackdrop::Get(window_)->RestoreBackdrop();
  267. // End overview if it was opened during dragging.
  268. OverviewController* overview_controller = Shell::Get()->overview_controller();
  269. if (overview_controller->InOverviewSession()) {
  270. overview_controller->EndOverview(OverviewEndAction::kDragWindowFromShelf,
  271. OverviewEnterExitType::kImmediateExit);
  272. }
  273. ReshowHiddenWindowsOnDragEnd();
  274. window_drag_result_ = ShelfWindowDragResult::kDragCanceled;
  275. // When the drag is cancelled, the window should restore to its original snap
  276. // position.
  277. OnDragEnded(previous_location_in_screen_,
  278. /*should_drop_window_in_overview=*/false,
  279. /*snap_position=*/initial_snap_position_);
  280. WindowState::Get(window_)->DeleteDragDetails();
  281. }
  282. bool DragWindowFromShelfController::IsDraggedWindowAnimating() const {
  283. return window_ && window_->layer()->GetAnimator()->is_animating();
  284. }
  285. void DragWindowFromShelfController::FinalizeDraggedWindow() {
  286. if (!window_drag_result_.has_value()) {
  287. started_in_overview_ = false;
  288. return;
  289. }
  290. DCHECK(!drag_started_);
  291. DCHECK(window_);
  292. OnDragEnded(previous_location_in_screen_,
  293. *window_drag_result_ == ShelfWindowDragResult::kGoToOverviewMode,
  294. end_snap_position_);
  295. }
  296. void DragWindowFromShelfController::OnWindowDestroying(aura::Window* window) {
  297. DCHECK_EQ(window_, window);
  298. CancelDrag();
  299. window_->RemoveObserver(this);
  300. window_ = nullptr;
  301. }
  302. void DragWindowFromShelfController::AddObserver(
  303. DragWindowFromShelfController::Observer* observer) {
  304. observers_.AddObserver(observer);
  305. }
  306. void DragWindowFromShelfController::RemoveObserver(
  307. DragWindowFromShelfController::Observer* observer) {
  308. observers_.RemoveObserver(observer);
  309. }
  310. void DragWindowFromShelfController::OnDragStarted(
  311. const gfx::PointF& location_in_screen) {
  312. drag_started_ = true;
  313. started_in_overview_ =
  314. Shell::Get()->overview_controller()->InOverviewSession();
  315. initial_location_in_screen_ = location_in_screen;
  316. previous_location_in_screen_ = location_in_screen;
  317. WindowState::Get(window_)->CreateDragDetails(
  318. initial_location_in_screen_, HTCLIENT, ::wm::WINDOW_MOVE_SOURCE_TOUCH);
  319. // Disable the backdrop on the dragged window during dragging.
  320. WindowBackdrop::Get(window_)->DisableBackdrop();
  321. // Hide all visible windows behind the dragged window during dragging.
  322. windows_hider_ = std::make_unique<WindowsHider>(window_);
  323. // Hide the home launcher until it's eligible to show it.
  324. Shell::Get()->app_list_controller()->OnWindowDragStarted();
  325. // Use the same dim and blur as in overview during dragging.
  326. RootWindowController::ForWindow(window_->GetRootWindow())
  327. ->wallpaper_widget_controller()
  328. ->SetWallpaperBlur(wallpaper_constants::kOverviewBlur);
  329. // If the dragged window is one of the snapped window in splitview, it needs
  330. // to be detached from splitview before start dragging.
  331. SplitViewController* split_view_controller =
  332. SplitViewController::Get(Shell::GetPrimaryRootWindow());
  333. // Preserve initial snap position
  334. if (split_view_controller->IsWindowInSplitView(window_)) {
  335. initial_snap_position_ =
  336. split_view_controller->GetPositionOfSnappedWindow(window_);
  337. }
  338. split_view_controller->OnWindowDragStarted(window_);
  339. // Note SplitViewController::OnWindowDragStarted() may open overview.
  340. if (Shell::Get()->overview_controller()->InOverviewSession())
  341. OnWindowDragStartedInOverview();
  342. }
  343. void DragWindowFromShelfController::OnDragEnded(
  344. const gfx::PointF& location_in_screen,
  345. bool should_drop_window_in_overview,
  346. SplitViewController::SnapPosition snap_position) {
  347. OverviewController* overview_controller = Shell::Get()->overview_controller();
  348. if (overview_controller->InOverviewSession()) {
  349. // Make sure overview is visible after drag ends.
  350. ShowOverviewDuringOrAfterDrag();
  351. OverviewSession* overview_session = overview_controller->overview_session();
  352. overview_session->ResetSplitViewDragIndicatorsWindowDraggingStates();
  353. // No need to reposition overview windows if we are not dropping the dragged
  354. // window into overview. Overview will either be exited or unchanged, and
  355. // the extra movement from existing window will just add unnecessary
  356. // movement which will also slow down our dragged window animation.
  357. if (!should_drop_window_in_overview)
  358. overview_session->SuspendReposition();
  359. overview_session->OnWindowDragEnded(
  360. window_, location_in_screen, should_drop_window_in_overview,
  361. /*snap=*/snap_position != SplitViewController::NONE);
  362. overview_session->ResumeReposition();
  363. }
  364. SplitViewController* split_view_controller =
  365. SplitViewController::Get(Shell::GetPrimaryRootWindow());
  366. if (split_view_controller->InSplitViewMode() ||
  367. snap_position != SplitViewController::NONE) {
  368. WindowState::Get(window_)->set_snap_action_source(
  369. WindowSnapActionSource::kDragUpFromShelfToSnap);
  370. split_view_controller->OnWindowDragEnded(
  371. window_, snap_position, gfx::ToRoundedPoint(location_in_screen));
  372. }
  373. // Scale-in-to-show home screen if home screen should be shown after drag
  374. // ends.
  375. Shell::Get()->app_list_controller()->OnWindowDragEnded(/*animate=*/true);
  376. // Clear the wallpaper dim and blur if not in overview after drag ends.
  377. // If in overview, the dim and blur will be cleared after overview ends.
  378. if (!overview_controller->InOverviewSession()) {
  379. RootWindowController::ForWindow(window_->GetRootWindow())
  380. ->wallpaper_widget_controller()
  381. ->SetWallpaperBlur(wallpaper_constants::kClear);
  382. }
  383. DCHECK(window_drag_result_.has_value());
  384. switch (*window_drag_result_) {
  385. case ShelfWindowDragResult::kGoToHomeScreen:
  386. ScaleDownWindowAfterDrag();
  387. windows_hider_.reset();
  388. break;
  389. case ShelfWindowDragResult::kRestoreToOriginalBounds:
  390. ScaleUpToRestoreWindowAfterDrag();
  391. // Do not reset |windows_hider_| here because
  392. // |ScaleUpToRestoreWindowAfterDrag()| ends up using |windows_hider_| in
  393. // an async manner.
  394. break;
  395. case ShelfWindowDragResult::kGoToOverviewMode:
  396. case ShelfWindowDragResult::kGoToSplitviewMode:
  397. case ShelfWindowDragResult::kDragCanceled:
  398. windows_hider_.reset();
  399. break;
  400. }
  401. window_drag_result_.reset();
  402. started_in_overview_ = false;
  403. }
  404. void DragWindowFromShelfController::UpdateDraggedWindow(
  405. const gfx::PointF& location_in_screen) {
  406. gfx::Rect bounds = window_->bounds();
  407. ::wm::ConvertRectToScreen(window_->parent(), &bounds);
  408. // Calculate the window's transform based on the location.
  409. // For scale, at |initial_location_in_screen_| or bounds.bottom(), the scale
  410. // is 1.0, and at the |min_y| position of its bounds, it reaches to its
  411. // minimum scale |kMinimumWindowScaleDuringDragging|. Calculate the desired
  412. // scale based on the current y position.
  413. const gfx::Rect display_bounds =
  414. display::Screen::GetScreen()
  415. ->GetDisplayNearestPoint(gfx::ToRoundedPoint(location_in_screen))
  416. .bounds();
  417. const float min_y = display_bounds.y() +
  418. display_bounds.height() * kMinYDisplayHeightRatio +
  419. kMinimumWindowScaleDuringDragging * bounds.height();
  420. float y_full =
  421. std::min(initial_location_in_screen_.y(), (float)bounds.bottom()) - min_y;
  422. float y_diff = location_in_screen.y() - min_y;
  423. float scale = (1.0f - kMinimumWindowScaleDuringDragging) * y_diff / y_full +
  424. kMinimumWindowScaleDuringDragging;
  425. scale = base::clamp(scale, /*min=*/kMinimumWindowScaleDuringDragging,
  426. /*max=*/1.f);
  427. // Calculate the desired translation so that the dragged window stays under
  428. // the finger during the dragging.
  429. // Since vertical drag doesn't start until after passing the top of the shelf,
  430. // the y calculations should be relative to the window bounds instead of
  431. // |initial_location_in_screen| (which is on the shelf)
  432. gfx::Transform transform;
  433. transform.Translate(
  434. (location_in_screen.x() - bounds.x()) -
  435. (initial_location_in_screen_.x() - bounds.x()) * scale,
  436. (location_in_screen.y() - bounds.y()) - bounds.height() * scale);
  437. transform.Scale(scale, scale);
  438. // The dragged window cannot exceed the top or bottom of the display. So
  439. // calculate the expected transformed bounds and then adjust the transform if
  440. // needed.
  441. gfx::RectF transformed_bounds(window_->bounds());
  442. gfx::Transform new_tranform = TransformAboutPivot(
  443. gfx::ToRoundedPoint(transformed_bounds.origin()), transform);
  444. new_tranform.TransformRect(&transformed_bounds);
  445. ::wm::TranslateRectToScreen(window_->parent(), &transformed_bounds);
  446. if (transformed_bounds.y() < display_bounds.y()) {
  447. transform.Translate(0,
  448. (display_bounds.y() - transformed_bounds.y()) / scale);
  449. } else if (transformed_bounds.bottom() > bounds.bottom()) {
  450. DCHECK_EQ(1.f, scale);
  451. transform.Translate(
  452. 0, (bounds.bottom() - transformed_bounds.bottom()) / scale);
  453. }
  454. SetTransform(window_, transform);
  455. }
  456. SplitViewController::SnapPosition
  457. DragWindowFromShelfController::GetSnapPosition(
  458. const gfx::PointF& location_in_screen) const {
  459. // if |location_in_screen| is close to the bottom of the screen and is
  460. // inside of GetReturnToMaximizedThreshold() threshold, we should not try to
  461. // snap the window.
  462. if (ShouldRestoreToOriginalBounds(location_in_screen, absl::nullopt))
  463. return SplitViewController::NONE;
  464. aura::Window* root_window = Shell::GetPrimaryRootWindow();
  465. SplitViewController::SnapPosition snap_position = ::ash::GetSnapPosition(
  466. root_window, window_, gfx::ToRoundedPoint(location_in_screen),
  467. gfx::ToRoundedPoint(initial_location_in_screen_),
  468. /*snap_distance_from_edge=*/kDistanceFromEdge,
  469. /*minimum_drag_distance=*/kMinDragDistance,
  470. /*horizontal_edge_inset=*/kScreenEdgeInsetForSnap,
  471. /*vertical_edge_inset=*/kScreenEdgeInsetForSnap);
  472. // For portrait mode, since the drag starts from the bottom of the screen,
  473. // we should only allow the window to snap to the top of the screen.
  474. const bool is_landscape = IsCurrentScreenOrientationLandscape();
  475. const bool is_primary = IsCurrentScreenOrientationPrimary();
  476. if (!is_landscape &&
  477. ((is_primary && snap_position == SplitViewController::RIGHT) ||
  478. (!is_primary && snap_position == SplitViewController::LEFT))) {
  479. snap_position = SplitViewController::NONE;
  480. }
  481. return snap_position;
  482. }
  483. bool DragWindowFromShelfController::ShouldRestoreToOriginalBounds(
  484. const gfx::PointF& location_in_screen,
  485. absl::optional<float> velocity_y) const {
  486. const gfx::Rect display_bounds =
  487. display::Screen::GetScreen()
  488. ->GetDisplayNearestPoint(gfx::ToRoundedPoint(location_in_screen))
  489. .bounds();
  490. gfx::RectF transformed_window_bounds =
  491. window_util::GetTransformedBounds(window_, /*top_inset=*/0);
  492. // If overview is invisible when the drag ends with downward velocity, we
  493. // should restore to original bounds.
  494. if (Shell::Get()->overview_controller()->InOverviewSession() &&
  495. !show_overview_windows_ && velocity_y.has_value() &&
  496. velocity_y.value() > 0) {
  497. return true;
  498. }
  499. // Otherwise restore the bounds if the downward vertical velocity exceeds the
  500. // threshold, or if the bottom of the dragged window is within the
  501. // GetReturnToMaximizedThreshold() threshold.
  502. return (velocity_y.has_value() &&
  503. velocity_y.value() >= kVelocityToRestoreBoundsThreshold) ||
  504. transformed_window_bounds.bottom() >
  505. display_bounds.bottom() - GetReturnToMaximizedThreshold();
  506. }
  507. bool DragWindowFromShelfController::ShouldGoToHomeScreen(
  508. const gfx::PointF& location_in_screen,
  509. absl::optional<float> velocity_y) const {
  510. // If the drag ends below the shelf, do not go to home screen (theoretically
  511. // it may happen in kExtended hotseat case when drag can start and end below
  512. // the shelf).
  513. if (location_in_screen.y() >=
  514. Shelf::ForWindow(window_)->GetIdealBoundsForWorkAreaCalculation().y()) {
  515. return false;
  516. }
  517. // Do not go home if we're in split screen.
  518. if (SplitViewController::Get(Shell::GetPrimaryRootWindow())
  519. ->InSplitViewMode()) {
  520. return false;
  521. }
  522. // If overview is invisible when the drag ends with upward velocity or no
  523. // velocity, we should go to home screen.
  524. if (Shell::Get()->overview_controller()->InOverviewSession() &&
  525. !show_overview_windows_ &&
  526. (!velocity_y.has_value() || velocity_y.value() <= 0)) {
  527. return true;
  528. }
  529. // Otherwise go home if the upward vertical velocity exceeds the threshold.
  530. return velocity_y.has_value() &&
  531. velocity_y.value() <= -kVelocityToHomeScreenThreshold;
  532. }
  533. SplitViewController::SnapPosition
  534. DragWindowFromShelfController::GetSnapPositionOnDragEnd(
  535. const gfx::PointF& location_in_screen,
  536. absl::optional<float> velocity_y) const {
  537. if (!Shell::Get()->overview_controller()->InOverviewSession() ||
  538. ShouldGoToHomeScreen(location_in_screen, velocity_y)) {
  539. return SplitViewController::NONE;
  540. }
  541. // When dragging ends but restore to original bounds, we should restore
  542. // window's initial snap position
  543. if (ShouldRestoreToOriginalBounds(location_in_screen, velocity_y))
  544. return initial_snap_position_;
  545. return GetSnapPosition(location_in_screen);
  546. }
  547. bool DragWindowFromShelfController::ShouldDropWindowInOverview(
  548. const gfx::PointF& location_in_screen,
  549. absl::optional<float> velocity_y) const {
  550. if (!Shell::Get()->overview_controller()->InOverviewSession())
  551. return false;
  552. if (ShouldGoToHomeScreen(location_in_screen, velocity_y))
  553. return false;
  554. const bool in_splitview =
  555. SplitViewController::Get(Shell::GetPrimaryRootWindow())
  556. ->InSplitViewMode();
  557. if (!in_splitview &&
  558. ShouldRestoreToOriginalBounds(location_in_screen, velocity_y)) {
  559. return false;
  560. }
  561. if (in_splitview) {
  562. if (velocity_y.has_value() &&
  563. velocity_y.value() <= -kVelocityToOverviewThreshold) {
  564. return true;
  565. }
  566. if (ShouldRestoreToOriginalBounds(location_in_screen, velocity_y))
  567. return false;
  568. }
  569. return GetSnapPositionOnDragEnd(location_in_screen, velocity_y) ==
  570. SplitViewController::NONE;
  571. }
  572. void DragWindowFromShelfController::ReshowHiddenWindowsOnDragEnd() {
  573. windows_hider_->RestoreWindowsVisibility();
  574. }
  575. void DragWindowFromShelfController::ShowOverviewDuringOrAfterDrag() {
  576. show_overview_timer_.Stop();
  577. OverviewController* overview_controller = Shell::Get()->overview_controller();
  578. if (!overview_controller->InOverviewSession())
  579. return;
  580. show_overview_windows_ = true;
  581. overview_controller->overview_session()->SetVisibleDuringWindowDragging(
  582. /*visible=*/true, /*animate=*/true);
  583. for (Observer& observer : observers_)
  584. observer.OnOverviewVisibilityChanged(true);
  585. }
  586. void DragWindowFromShelfController::HideOverviewDuringDrag() {
  587. show_overview_windows_ = false;
  588. OverviewController* overview_controller = Shell::Get()->overview_controller();
  589. if (!overview_controller->InOverviewSession())
  590. return;
  591. overview_controller->overview_session()->SetVisibleDuringWindowDragging(
  592. /*visible=*/false,
  593. /*animate=*/false);
  594. for (Observer& observer : observers_)
  595. observer.OnOverviewVisibilityChanged(false);
  596. }
  597. void DragWindowFromShelfController::ScaleDownWindowAfterDrag() {
  598. // Notify home screen controller that the home screen is about to be shown, so
  599. // home screen and shelf start updating their state as the window is
  600. // minimizing.
  601. Shell::Get()->app_list_controller()->OnHomeLauncherPositionChanged(
  602. /*percent_shown=*/100,
  603. display::Screen::GetScreen()->GetPrimaryDisplay().id());
  604. (new WindowScaleAnimation(
  605. window_, WindowScaleAnimation::WindowScaleType::kScaleDownToShelf,
  606. base::BindOnce(
  607. &DragWindowFromShelfController::OnWindowScaledDownAfterDrag,
  608. weak_ptr_factory_.GetWeakPtr())))
  609. ->Start();
  610. }
  611. void DragWindowFromShelfController::OnWindowScaledDownAfterDrag() {
  612. AppListControllerImpl* app_list_controller =
  613. Shell::Get()->app_list_controller();
  614. if (!app_list_controller)
  615. return;
  616. app_list_controller->OnHomeLauncherAnimationComplete(
  617. /*shown=*/true, display::Screen::GetScreen()->GetPrimaryDisplay().id());
  618. }
  619. void DragWindowFromShelfController::ScaleUpToRestoreWindowAfterDrag() {
  620. (new WindowScaleAnimation(
  621. window_, WindowScaleAnimation::WindowScaleType::kScaleUpToRestore,
  622. base::BindOnce(
  623. &DragWindowFromShelfController::OnWindowRestoredToOrignalBounds,
  624. weak_ptr_factory_.GetWeakPtr(),
  625. /*should_end_overview=*/!started_in_overview_)))
  626. ->Start();
  627. }
  628. void DragWindowFromShelfController::OnWindowRestoredToOrignalBounds(
  629. bool end_overview) {
  630. base::AutoReset<bool> auto_reset(&during_window_restoration_callback_, true);
  631. if (end_overview) {
  632. Shell::Get()->overview_controller()->EndOverview(
  633. OverviewEndAction::kDragWindowFromShelf,
  634. OverviewEnterExitType::kImmediateExit);
  635. }
  636. ReshowHiddenWindowsOnDragEnd();
  637. }
  638. void DragWindowFromShelfController::OnWindowDragStartedInOverview() {
  639. OverviewSession* overview_session =
  640. Shell::Get()->overview_controller()->overview_session();
  641. DCHECK(overview_session);
  642. overview_session->OnWindowDragStarted(window_, /*animate=*/false);
  643. if (ShouldAllowSplitView())
  644. overview_session->SetSplitViewDragIndicatorsDraggedWindow(window_);
  645. // Hide overview windows first and fade in the windows after delaying
  646. // kShowOverviewTimeWhenDragSuspend.
  647. HideOverviewDuringDrag();
  648. }
  649. } // namespace ash