Commit 363a1580 authored by Ahmed Fakhry's avatar Ahmed Fakhry Committed by Commit Bot

Virtual Desks 5: Implement desk switch animations.

When a desk is activated, this CL adds a horizontal
movement from the starting (current) desk to the
ending (to be activated) desk on all displays, since
a desk spans all displays.

Demos: https://bugs.chromium.org/p/chromium/issues/detail?id=866622#c24

BUG=866622
TEST=Manual, added tests to increase code coverage in
     the case of multi displays.

Change-Id: I901b000a6ff89173d70e3ab07cbb7656c34d8357
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1591000
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarSammie Quon <sammiequon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#657376}
parent 88faf3bf
......@@ -1084,6 +1084,8 @@ component("ash") {
"wm/desks/desks_util.h",
"wm/desks/new_desk_button.cc",
"wm/desks/new_desk_button.h",
"wm/desks/root_window_desk_switch_animator.cc",
"wm/desks/root_window_desk_switch_animator.h",
"wm/drag_details.cc",
"wm/drag_details.h",
"wm/drag_window_controller.cc",
......
......@@ -152,7 +152,6 @@ void DesksBarView::ButtonPressed(views::Button* sender,
for (auto& mini_view : mini_views_) {
if (mini_view.get() == sender) {
controller->ActivateDesk(mini_view->desk());
Shell::Get()->overview_controller()->OnSelectionEnded();
return;
}
}
......@@ -205,6 +204,8 @@ void DesksBarView::OnDeskActivationChanged(const Desk* activated,
}
}
void DesksBarView::OnDeskSwitchAnimationFinished() {}
void DesksBarView::UpdateNewDeskButtonState() {
new_desk_button_->SetEnabled(DesksController::Get()->CanCreateDesks());
}
......
......@@ -63,6 +63,7 @@ class ASH_EXPORT DesksBarView : public views::View,
void OnDeskRemoved(const Desk* desk) override;
void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override;
void OnDeskSwitchAnimationFinished() override;
private:
// This is called on initialization or when a new desk is created to create
......
......@@ -10,11 +10,14 @@
#include "ash/shell.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/desks/root_window_desk_switch_animator.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/window_util.h"
#include "base/auto_reset.h"
#include "base/logging.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor.h"
namespace ash {
......@@ -79,6 +82,10 @@ void DesksController::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
bool DesksController::AreDesksBeingModified() const {
return are_desks_being_modified_ || !desk_switch_animators_.empty();
}
bool DesksController::CanCreateDesks() const {
// TODO(afakhry): Disable creating new desks in tablet mode.
return desks_.size() < desks_util::kMaxNumberOfDesks;
......@@ -176,7 +183,27 @@ void DesksController::RemoveDesk(const Desk* desk) {
}
void DesksController::ActivateDesk(const Desk* desk) {
ActivateDeskInternal(desk, /*update_window_activation=*/true);
DCHECK(HasDesk(desk));
if (desk == active_desk_)
return;
// New desks are always added at the end of the list to the right of existing
// desks. Therefore, desks at lower indices are located on the left of desks
// with higher indices.
const bool move_left = GetDeskIndex(active_desk_) < GetDeskIndex(desk);
for (auto* root : Shell::GetAllRootWindows()) {
desk_switch_animators_.emplace_back(
std::make_unique<RootWindowDeskSwitchAnimator>(root, desk, this,
move_left));
}
// Once all animators are created, start them all by taking the starting desk
// screenshots. 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.
for (auto& animator : desk_switch_animators_)
animator->TakeStartingDeskScreenshot();
}
void DesksController::OnRootWindowAdded(aura::Window* root_window) {
......@@ -189,6 +216,76 @@ void DesksController::OnRootWindowClosing(aura::Window* root_window) {
desk->OnRootWindowClosing(root_window);
}
void DesksController::OnStartingDeskScreenshotTaken(const Desk* ending_desk) {
DCHECK(!desk_switch_animators_.empty());
// Once all starting desk screenshots on all roots are taken and placed on the
// screens, do the actual desk activation logic.
for (const auto& animator : desk_switch_animators_) {
if (!animator->starting_desk_screenshot_taken())
return;
}
// Extend the compositors' timeouts in order to prevents any repaints until
// the desks are switched and overview mode exits.
const auto roots = Shell::GetAllRootWindows();
for (auto* root : roots)
root->GetHost()->compositor()->SetAllowLocksToExtendTimeout(true);
const bool is_selecting = Shell::Get()->overview_controller()->IsSelecting();
ActivateDeskInternal(ending_desk, /*update_window_activation=*/true);
// Activating a desk should not change the overview mode state.
DCHECK_EQ(is_selecting, Shell::Get()->overview_controller()->IsSelecting());
if (is_selecting) {
// Exit overview mode immediately without any animations before taking the
// ending desk screenshot. This makes sure that the ending desk
// screenshot will only show the windows in that desk, not overview stuff.
Shell::Get()->overview_controller()->ToggleOverview(
OverviewSession::EnterExitOverviewType::kImmediateExit);
}
for (auto* root : roots)
root->GetHost()->compositor()->SetAllowLocksToExtendTimeout(false);
// Continue the second phase of the animation by taking the ending desk
// screenshot and actually animating the layers.
for (auto& animator : desk_switch_animators_)
animator->TakeEndingDeskScreenshot();
}
void DesksController::OnEndingDeskScreenshotTaken() {
DCHECK(!desk_switch_animators_.empty());
// Once all ending desk screenshots on all roots are taken, start the
// animation on all roots at the same time, so that they look synchrnoized.
for (const auto& animator : desk_switch_animators_) {
if (!animator->ending_desk_screenshot_taken())
return;
}
for (auto& animator : desk_switch_animators_)
animator->StartAnimation();
}
void DesksController::OnDeskSwitchAnimationFinished() {
DCHECK(!desk_switch_animators_.empty());
// Once all desk switch animations on all roots finish, destroy all the
// animators.
for (const auto& animator : desk_switch_animators_) {
if (!animator->animation_finished())
return;
}
desk_switch_animators_.clear();
for (auto& observer : observers_)
observer.OnDeskSwitchAnimationFinished();
}
bool DesksController::HasDesk(const Desk* desk) const {
auto iter = std::find_if(
desks_.begin(), desks_.end(),
......@@ -196,6 +293,16 @@ bool DesksController::HasDesk(const Desk* desk) const {
return iter != desks_.end();
}
int DesksController::GetDeskIndex(const Desk* desk) const {
for (size_t i = 0; i < desks_.size(); ++i) {
if (desk == desks_[i].get())
return i;
}
NOTREACHED();
return -1;
}
void DesksController::ActivateDeskInternal(const Desk* desk,
bool update_window_activation) {
DCHECK(HasDesk(desk));
......@@ -218,8 +325,6 @@ void DesksController::ActivateDeskInternal(const Desk* desk,
for (auto& observer : observers_)
observer.OnDeskActivationChanged(active_desk_, old_active);
// TODO(afakhry): Do desk activation animation.
}
} // namespace ash
......@@ -10,6 +10,7 @@
#include <vector>
#include "ash/ash_export.h"
#include "ash/wm/desks/root_window_desk_switch_animator.h"
#include "base/macros.h"
#include "base/observer_list.h"
......@@ -23,7 +24,8 @@ class Desk;
// Defines a controller for creating, destroying and managing virtual desks and
// their windows.
class ASH_EXPORT DesksController {
class ASH_EXPORT DesksController
: public RootWindowDeskSwitchAnimator::Delegate {
public:
class Observer {
public:
......@@ -41,12 +43,15 @@ class ASH_EXPORT DesksController {
virtual void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) = 0;
// Called when the desk switch animations on all root windows finish.
virtual void OnDeskSwitchAnimationFinished() = 0;
protected:
virtual ~Observer() = default;
};
DesksController();
~DesksController();
~DesksController() override;
// Convenience method for returning the DesksController instance. The actual
// instance is created and owned by Shell.
......@@ -56,11 +61,14 @@ class ASH_EXPORT DesksController {
const Desk* active_desk() const { return active_desk_; }
bool are_desks_being_modified() const { return are_desks_being_modified_; }
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Returns true if desks are being modified due to desk creation, removal, or
// activation. It also returns true while the desk switch animation is in
// progress.
bool AreDesksBeingModified() const;
// Returns true if we haven't reached the maximum allowed number of desks.
bool CanCreateDesks() const;
......@@ -75,10 +83,11 @@ class ASH_EXPORT DesksController {
// CanRemoveDesks() must be checked before this.
void RemoveDesk(const Desk* desk);
// Activates the given |desk| and deactivates the currently active one. |desk|
// has to be an existing desk. The active window on the currently active desk
// will be deactivated, and the most-recently used window from the
// newly-activated desk will be activated.
// Performs the desk switch animation on all root windows to activate the
// given |desk| and to deactivate the currently active one. |desk| has to be
// an existing desk. The active window on the currently active desk will be
// deactivated, and the most-recently used window from the newly-activated
// desk will be activated.
void ActivateDesk(const Desk* desk);
// Called explicitly by the RootWindowController when a root window has been
......@@ -86,9 +95,16 @@ class ASH_EXPORT DesksController {
void OnRootWindowAdded(aura::Window* root_window);
void OnRootWindowClosing(aura::Window* root_window);
// RootWindowDeskSwitchAnimator::Delegate:
void OnStartingDeskScreenshotTaken(const Desk* ending_desk) override;
void OnEndingDeskScreenshotTaken() override;
void OnDeskSwitchAnimationFinished() override;
private:
bool HasDesk(const Desk* desk) const;
int GetDeskIndex(const Desk* desk) const;
// Activates the given |desk| and deactivates the currently active one. |desk|
// has to be an existing desk. If |update_window_activation| is true,
// the active desk on the deactivated desk will be deactivated, and the most-
......@@ -109,6 +125,11 @@ class ASH_EXPORT DesksController {
// mode as a result of desks modifications.
bool are_desks_being_modified_ = false;
// 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_;
// A free list of desk container IDs to be used for newly-created desks. New
// desks pops from this queue and removed desks's associated container IDs are
// re-pushed on this queue.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -304,7 +304,8 @@ void OverviewSession::Shutdown() {
for (std::unique_ptr<OverviewGrid>& overview_grid : grid_list_) {
// During shutdown, do not animate all windows in overview if we need to
// animate the snapped window.
if (overview_grid->should_animate_when_exiting()) {
if (overview_grid->should_animate_when_exiting() &&
enter_exit_overview_type_ != EnterExitOverviewType::kImmediateExit) {
overview_grid->CalculateWindowListAnimationStates(
selected_item_ &&
selected_item_->overview_grid() == overview_grid.get()
......@@ -704,7 +705,7 @@ void OverviewSession::OnWindowActivating(
return;
if (features::IsVirtualDesksEnabled() &&
DesksController::Get()->are_desks_being_modified()) {
DesksController::Get()->AreDesksBeingModified()) {
// Activating a desk from its mini view will activate its most-recently used
// window, but this should not result in ending overview mode now.
// DesksBarView will end it explicitly. This will become significant when
......@@ -807,7 +808,7 @@ void OverviewSession::OnWindowHierarchyChanged(
// of that desk to the associated container of another desk. This is a window
// hierarchy change that shouldn't result in exiting overview mode.
if (features::IsVirtualDesksEnabled() &&
DesksController::Get()->are_desks_being_modified()) {
DesksController::Get()->AreDesksBeingModified()) {
return;
}
......
......@@ -22,6 +22,7 @@
#include "ash/wm/window_transient_descendant_iterator.h"
#include "ash/wm/wm_event.h"
#include "base/no_destructor.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/scoped_canvas.h"
......@@ -120,7 +121,8 @@ void FadeOutWidgetAndMaybeSlideOnExit(std::unique_ptr<views::Widget> widget,
}
void ImmediatelyCloseWidgetOnExit(std::unique_ptr<views::Widget> widget) {
ScopedAnimationDisabler animation_disabler(widget->GetNativeWindow());
widget->GetNativeWindow()->SetProperty(aura::client::kAnimationsDisabledKey,
true);
widget->Close();
widget.reset();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment