Commit 35147c4b authored by varkha's avatar varkha Committed by Commit bot

Initializes overview shield with the same opacity as the shelf.

Completes shield opacity animation after overview closes.

This CL deals with the transition into and out of the overview
mode.
When the shelf is in SHELF_BACKGROUND_MAXIMIZED state the shield starts
black and animates to 70% black.
When the shelf is transparent or semi-transparent the shield starts
transparent and animates to 70% black.
When overview mode finishes an observer is installed on the shield
widget that deletes itself and the widget once the opacity animation
completes.

BUG=624443

Review-Url: https://codereview.chromium.org/2141133002
Cr-Commit-Position: refs/heads/master@{#406122}
parent 4d67cd98
...@@ -357,6 +357,8 @@ ...@@ -357,6 +357,8 @@
'common/wm/maximize_mode/workspace_backdrop_delegate.h', 'common/wm/maximize_mode/workspace_backdrop_delegate.h',
'common/wm/mru_window_tracker.cc', 'common/wm/mru_window_tracker.cc',
'common/wm/mru_window_tracker.h', 'common/wm/mru_window_tracker.h',
'common/wm/overview/cleanup_animation_observer.cc',
'common/wm/overview/cleanup_animation_observer.h',
'common/wm/overview/overview_animation_type.h', 'common/wm/overview/overview_animation_type.h',
'common/wm/overview/scoped_overview_animation_settings.h', 'common/wm/overview/scoped_overview_animation_settings.h',
'common/wm/overview/scoped_overview_animation_settings_factory.cc', 'common/wm/overview/scoped_overview_animation_settings_factory.cc',
...@@ -913,6 +915,7 @@ ...@@ -913,6 +915,7 @@
'common/system/tray/tray_details_view_unittest.cc', 'common/system/tray/tray_details_view_unittest.cc',
'common/system/update/tray_update_unittest.cc', 'common/system/update/tray_update_unittest.cc',
'common/system/user/tray_user_unittest.cc', 'common/system/user/tray_user_unittest.cc',
'common/wm/overview/cleanup_animation_observer_unittest.cc',
'content/display/screen_orientation_controller_chromeos_unittest.cc', 'content/display/screen_orientation_controller_chromeos_unittest.cc',
'content/keyboard_overlay/keyboard_overlay_delegate_unittest.cc', 'content/keyboard_overlay/keyboard_overlay_delegate_unittest.cc',
'content/keyboard_overlay/keyboard_overlay_view_unittest.cc', 'content/keyboard_overlay/keyboard_overlay_view_unittest.cc',
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/common/wm/overview/cleanup_animation_observer.h"
#include "ui/views/widget/widget.h"
namespace ash {
CleanupAnimationObserver::CleanupAnimationObserver(
std::unique_ptr<views::Widget> widget)
: widget_(std::move(widget)), owner_(nullptr) {
DCHECK(widget_);
}
CleanupAnimationObserver::~CleanupAnimationObserver() {}
void CleanupAnimationObserver::OnImplicitAnimationsCompleted() {
// |widget_| may get reset if Shutdown() is called prior to this method.
if (!widget_)
return;
if (owner_) {
owner_->RemoveAndDestroyAnimationObserver(this);
return;
}
delete this;
}
void CleanupAnimationObserver::SetOwner(WindowSelectorDelegate* owner) {
owner_ = owner;
}
void CleanupAnimationObserver::Shutdown() {
widget_.reset();
owner_ = nullptr;
}
} // namespace ash
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_COMMON_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_
#define ASH_COMMON_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_
#include <memory>
#include "ash/ash_export.h"
#include "ash/common/wm/overview/window_selector_delegate.h"
#include "base/macros.h"
#include "ui/compositor/layer_animation_observer.h"
namespace views {
class Widget;
}
namespace ash {
// An observer which holds onto the passed widget until the animation is
// complete.
class ASH_EXPORT CleanupAnimationObserver
: public ui::ImplicitAnimationObserver,
public DelayedAnimationObserver {
public:
explicit CleanupAnimationObserver(std::unique_ptr<views::Widget> widget);
~CleanupAnimationObserver() override;
// ui::ImplicitAnimationObserver:
// TODO(varkha): Look into all cases when animations are not started such as
// zero-duration animations and ensure that the object lifetime is handled.
void OnImplicitAnimationsCompleted() override;
// DelayedAnimationObserver:
void SetOwner(WindowSelectorDelegate* owner) override;
void Shutdown() override;
private:
std::unique_ptr<views::Widget> widget_;
WindowSelectorDelegate* owner_;
DISALLOW_COPY_AND_ASSIGN(CleanupAnimationObserver);
};
} // namespace ash
#endif // ASH_COMMON_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include "ash/common/wm/overview/cleanup_animation_observer.h"
#include "ash/common/wm/overview/window_selector_delegate.h"
#include "ash/common/wm_lookup.h"
#include "ash/common/wm_window.h"
#include "ash/test/ash_test_base.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
namespace ash {
namespace {
class TestWindowSelectorDelegate : public WindowSelectorDelegate {
public:
TestWindowSelectorDelegate() = default;
~TestWindowSelectorDelegate() override {
// Destroy widgets that may be still animating if shell shuts down soon
// after exiting overview mode.
for (std::unique_ptr<DelayedAnimationObserver>& observer : observers_)
observer->Shutdown();
}
// WindowSelectorDelegate:
void OnSelectionEnded() override {}
void AddDelayedAnimationObserver(
std::unique_ptr<DelayedAnimationObserver> animation_observer) override {
animation_observer->SetOwner(this);
observers_.push_back(std::move(animation_observer));
}
void RemoveAndDestroyAnimationObserver(
DelayedAnimationObserver* animation_observer) override {
class IsEqual {
public:
explicit IsEqual(DelayedAnimationObserver* animation_observer)
: animation_observer_(animation_observer) {}
bool operator()(const std::unique_ptr<DelayedAnimationObserver>& other) {
return (other.get() == animation_observer_);
}
private:
const DelayedAnimationObserver* animation_observer_;
};
observers_.erase(std::remove_if(observers_.begin(), observers_.end(),
IsEqual(animation_observer)),
observers_.end());
}
private:
std::vector<std::unique_ptr<DelayedAnimationObserver>> observers_;
DISALLOW_COPY_AND_ASSIGN(TestWindowSelectorDelegate);
};
class CleanupAnimationObserverTest : public test::AshTestBase,
public views::WidgetObserver {
public:
CleanupAnimationObserverTest() = default;
~CleanupAnimationObserverTest() override {
if (widget_)
widget_->RemoveObserver(this);
}
// Creates a Widget containing a Window with the given |bounds|. This should
// be used when the test requires a Widget. For example any test that will
// cause a window to be closed via
// views::Widget::GetWidgetForNativeView(window)->Close().
std::unique_ptr<views::Widget> CreateWindowWidget(const gfx::Rect& bounds) {
std::unique_ptr<views::Widget> widget(new views::Widget);
views::Widget::InitParams params;
params.bounds = bounds;
params.type = views::Widget::InitParams::TYPE_WINDOW;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
widget->Show();
ParentWindowInPrimaryRootWindow(widget->GetNativeWindow());
widget->AddObserver(this);
widget_ = widget.get();
return widget;
}
protected:
bool widget_destroyed() { return !widget_; }
private:
void OnWidgetDestroyed(views::Widget* widget) override {
if (widget_ == widget)
widget_ = nullptr;
}
views::Widget* widget_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(CleanupAnimationObserverTest);
};
} // namespace
// Tests that basic create-destroy sequence does not crash.
TEST_F(CleanupAnimationObserverTest, CreateDestroy) {
TestWindowSelectorDelegate delegate;
std::unique_ptr<views::Widget> widget(
CreateWindowWidget(gfx::Rect(0, 0, 40, 40)));
std::unique_ptr<CleanupAnimationObserver> observer(
new CleanupAnimationObserver(std::move(widget)));
delegate.AddDelayedAnimationObserver(std::move(observer));
}
// Tests that completing animation deletes the animation observer and the
// test widget and that deleting the WindowSelectorDelegate instance which
// owns the observer does not crash.
TEST_F(CleanupAnimationObserverTest, CreateAnimateComplete) {
TestWindowSelectorDelegate delegate;
std::unique_ptr<views::Widget> widget(
CreateWindowWidget(gfx::Rect(0, 0, 40, 40)));
WmWindow* widget_window = WmLookup::Get()->GetWindowForWidget(widget.get());
{
ui::ScopedLayerAnimationSettings animation_settings(
widget_window->GetLayer()->GetAnimator());
animation_settings.SetTransitionDuration(
base::TimeDelta::FromMilliseconds(1000));
animation_settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
std::unique_ptr<CleanupAnimationObserver> observer(
new CleanupAnimationObserver(std::move(widget)));
animation_settings.AddObserver(observer.get());
delegate.AddDelayedAnimationObserver(std::move(observer));
widget_window->SetBounds(gfx::Rect(50, 50, 60, 60));
}
// The widget should be destroyed when |animation_settings| gets out of scope
// which in absence of NON_ZERO_DURATION animation duration mode completes
// the animation and calls OnImplicitAnimationsCompleted() on the cleanup
// observer and auto-deletes the owned widget.
EXPECT_TRUE(widget_destroyed());
// TestWindowSelectorDelegate going out of scope should not crash.
}
// Tests that starting an animation and exiting doesn't crash. If not for
// TestWindowSelectorDelegate calling Shutdown() on a CleanupAnimationObserver
// instance in destructor, this test would have crashed.
TEST_F(CleanupAnimationObserverTest, CreateAnimateShutdown) {
TestWindowSelectorDelegate delegate;
std::unique_ptr<views::Widget> widget(
CreateWindowWidget(gfx::Rect(0, 0, 40, 40)));
WmWindow* widget_window = WmLookup::Get()->GetWindowForWidget(widget.get());
{
// Normal animations for tests have ZERO_DURATION, make sure we are actually
// animating the movement.
ui::ScopedAnimationDurationScaleMode animation_scale_mode(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
ui::ScopedLayerAnimationSettings animation_settings(
widget_window->GetLayer()->GetAnimator());
animation_settings.SetTransitionDuration(
base::TimeDelta::FromMilliseconds(1000));
animation_settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
std::unique_ptr<CleanupAnimationObserver> observer(
new CleanupAnimationObserver(std::move(widget)));
animation_settings.AddObserver(observer.get());
delegate.AddDelayedAnimationObserver(std::move(observer));
widget_window->SetBounds(gfx::Rect(50, 50, 60, 60));
}
// The widget still exists.
EXPECT_FALSE(widget_destroyed());
// The test widget is auto-deleted when |delegate| that owns it goes out of
// scope. The animation is still active when this happens which should not
// crash.
}
} // namespace ash
...@@ -12,11 +12,15 @@ ...@@ -12,11 +12,15 @@
#include "ash/common/ash_switches.h" #include "ash/common/ash_switches.h"
#include "ash/common/material_design/material_design_controller.h" #include "ash/common/material_design/material_design_controller.h"
#include "ash/common/shelf/shelf_types.h"
#include "ash/common/shelf/wm_shelf.h"
#include "ash/common/shell_window_ids.h" #include "ash/common/shell_window_ids.h"
#include "ash/common/wm/overview/cleanup_animation_observer.h"
#include "ash/common/wm/overview/scoped_overview_animation_settings.h" #include "ash/common/wm/overview/scoped_overview_animation_settings.h"
#include "ash/common/wm/overview/scoped_overview_animation_settings_factory.h" #include "ash/common/wm/overview/scoped_overview_animation_settings_factory.h"
#include "ash/common/wm/overview/scoped_transform_overview_window.h" #include "ash/common/wm/overview/scoped_transform_overview_window.h"
#include "ash/common/wm/overview/window_selector.h" #include "ash/common/wm/overview/window_selector.h"
#include "ash/common/wm/overview/window_selector_delegate.h"
#include "ash/common/wm/overview/window_selector_item.h" #include "ash/common/wm/overview/window_selector_item.h"
#include "ash/common/wm/window_state.h" #include "ash/common/wm/window_state.h"
#include "ash/common/wm/wm_screen_util.h" #include "ash/common/wm/wm_screen_util.h"
...@@ -48,34 +52,6 @@ namespace { ...@@ -48,34 +52,6 @@ namespace {
using Windows = std::vector<WmWindow*>; using Windows = std::vector<WmWindow*>;
// An observer which holds onto the passed widget until the animation is
// complete.
class CleanupWidgetAfterAnimationObserver
: public ui::ImplicitAnimationObserver {
public:
explicit CleanupWidgetAfterAnimationObserver(
std::unique_ptr<views::Widget> widget);
~CleanupWidgetAfterAnimationObserver() override;
// ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override;
private:
std::unique_ptr<views::Widget> widget_;
DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver);
};
CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver(
std::unique_ptr<views::Widget> widget)
: widget_(std::move(widget)) {}
CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() {}
void CleanupWidgetAfterAnimationObserver::OnImplicitAnimationsCompleted() {
delete this;
}
// A comparator for locating a given target window. // A comparator for locating a given target window.
struct WindowSelectorItemComparator { struct WindowSelectorItemComparator {
explicit WindowSelectorItemComparator(const WmWindow* target_window) explicit WindowSelectorItemComparator(const WmWindow* target_window)
...@@ -100,7 +76,8 @@ const int kMinCardsMajor = 3; ...@@ -100,7 +76,8 @@ const int kMinCardsMajor = 3;
const int kOverviewSelectorTransitionMilliseconds = 250; const int kOverviewSelectorTransitionMilliseconds = 250;
// The color and opacity of the screen shield in overview. // The color and opacity of the screen shield in overview.
const SkColor kShieldColor = SkColorSetARGB(178, 0, 0, 0); const SkColor kShieldColor = SkColorSetARGB(255, 0, 0, 0);
const float kShieldOpacity = 0.7f;
// The color and opacity of the overview selector. // The color and opacity of the overview selector.
const SkColor kWindowSelectionColor = SkColorSetARGB(128, 0, 0, 0); const SkColor kWindowSelectionColor = SkColorSetARGB(128, 0, 0, 0);
...@@ -354,11 +331,13 @@ void ReorderItemsGreedyLeastMovement(std::vector<WmWindow*>* items, ...@@ -354,11 +331,13 @@ void ReorderItemsGreedyLeastMovement(std::vector<WmWindow*>* items,
// |root_window|'s default container and having |background_color|. // |root_window|'s default container and having |background_color|.
// When |border_thickness| is non-zero, a border is created having // When |border_thickness| is non-zero, a border is created having
// |border_color|, otherwise |border_color| parameter is ignored. // |border_color|, otherwise |border_color| parameter is ignored.
// The new background widget starts with |initial_opacity| and then fades in.
views::Widget* CreateBackgroundWidget(WmWindow* root_window, views::Widget* CreateBackgroundWidget(WmWindow* root_window,
SkColor background_color, SkColor background_color,
int border_thickness, int border_thickness,
int border_radius, int border_radius,
SkColor border_color) { SkColor border_color,
float initial_opacity) {
views::Widget* widget = new views::Widget; views::Widget* widget = new views::Widget;
views::Widget::InitParams params; views::Widget::InitParams params;
params.type = views::Widget::InitParams::TYPE_POPUP; params.type = views::Widget::InitParams::TYPE_POPUP;
...@@ -396,8 +375,7 @@ views::Widget* CreateBackgroundWidget(WmWindow* root_window, ...@@ -396,8 +375,7 @@ views::Widget* CreateBackgroundWidget(WmWindow* root_window,
widget->SetContentsView(content_view); widget->SetContentsView(content_view);
widget_window->GetParent()->StackChildAtTop(widget_window); widget_window->GetParent()->StackChildAtTop(widget_window);
widget->Show(); widget->Show();
// New background widget starts with 0 opacity and then fades in. widget_window->SetOpacity(initial_opacity);
widget_window->SetOpacity(0.f);
return widget; return widget;
} }
...@@ -436,6 +414,34 @@ WindowGrid::~WindowGrid() { ...@@ -436,6 +414,34 @@ WindowGrid::~WindowGrid() {
window->RemoveObserver(this); window->RemoveObserver(this);
} }
void WindowGrid::Shutdown() {
if (shield_widget_) {
// Fade out the shield widget. This animation continues past the lifetime
// of |this|.
WmWindow* widget_window =
WmLookup::Get()->GetWindowForWidget(shield_widget_.get());
ui::ScopedLayerAnimationSettings animation_settings(
widget_window->GetLayer()->GetAnimator());
animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
kOverviewSelectorTransitionMilliseconds));
animation_settings.SetTweenType(gfx::Tween::EASE_IN);
animation_settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
// CleanupAnimationObserver will delete itself (and the shield widget) when
// the opacity animation is complete.
// Ownership over the observer is passed to the window_selector_->delegate()
// which has longer lifetime so that animations can continue even after the
// overview mode is shut down.
views::Widget* shield_widget = shield_widget_.get();
std::unique_ptr<CleanupAnimationObserver> observer(
new CleanupAnimationObserver(std::move(shield_widget_)));
animation_settings.AddObserver(observer.get());
window_selector_->delegate()->AddDelayedAnimationObserver(
std::move(observer));
shield_widget->SetOpacity(0.f);
}
}
void WindowGrid::PrepareForOverview() { void WindowGrid::PrepareForOverview() {
if (ash::MaterialDesignController::IsOverviewMaterial()) if (ash::MaterialDesignController::IsOverviewMaterial())
InitShieldWidget(); InitShieldWidget();
...@@ -794,8 +800,17 @@ void WindowGrid::OnWindowBoundsChanged(WmWindow* window, ...@@ -794,8 +800,17 @@ void WindowGrid::OnWindowBoundsChanged(WmWindow* window,
} }
void WindowGrid::InitShieldWidget() { void WindowGrid::InitShieldWidget() {
shield_widget_.reset(CreateBackgroundWidget(root_window_, kShieldColor, 0, 0, // TODO(varkha): The code assumes that SHELF_BACKGROUND_MAXIMIZED is
SK_ColorTRANSPARENT)); // synonymous with a black shelf background. Update this code if that
// assumption is no longer valid.
const float initial_opacity =
(root_window_->GetRootWindowController()
->GetShelf()
->GetBackgroundType() == SHELF_BACKGROUND_MAXIMIZED)
? 1.f
: 0.f;
shield_widget_.reset(CreateBackgroundWidget(
root_window_, kShieldColor, 0, 0, SK_ColorTRANSPARENT, initial_opacity));
WmWindow* widget_window = WmWindow* widget_window =
WmLookup::Get()->GetWindowForWidget(shield_widget_.get()); WmLookup::Get()->GetWindowForWidget(shield_widget_.get());
...@@ -809,7 +824,7 @@ void WindowGrid::InitShieldWidget() { ...@@ -809,7 +824,7 @@ void WindowGrid::InitShieldWidget() {
animation_settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); animation_settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
animation_settings.SetPreemptionStrategy( animation_settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
shield_widget_->SetOpacity(1.f); shield_widget_->SetOpacity(kShieldOpacity);
} }
void WindowGrid::InitSelectionWidget(WindowSelector::Direction direction) { void WindowGrid::InitSelectionWidget(WindowSelector::Direction direction) {
...@@ -822,9 +837,9 @@ void WindowGrid::InitSelectionWidget(WindowSelector::Direction direction) { ...@@ -822,9 +837,9 @@ void WindowGrid::InitSelectionWidget(WindowSelector::Direction direction) {
material ? kWindowSelectionColorMD : kWindowSelectionColor; material ? kWindowSelectionColorMD : kWindowSelectionColor;
const int border_radius = const int border_radius =
material ? kWindowSelectionRadiusMD : kWindowSelectionRadius; material ? kWindowSelectionRadiusMD : kWindowSelectionRadius;
selection_widget_.reset(CreateBackgroundWidget(root_window_, selection_color, selection_widget_.reset(
border_thickness, CreateBackgroundWidget(root_window_, selection_color, border_thickness,
border_radius, border_color)); border_radius, border_color, 0.f));
WmWindow* widget_window = WmWindow* widget_window =
WmLookup::Get()->GetWindowForWidget(selection_widget_.get()); WmLookup::Get()->GetWindowForWidget(selection_widget_.get());
const gfx::Rect target_bounds = const gfx::Rect target_bounds =
...@@ -864,10 +879,16 @@ void WindowGrid::MoveSelectionWidget(WindowSelector::Direction direction, ...@@ -864,10 +879,16 @@ void WindowGrid::MoveSelectionWidget(WindowSelector::Direction direction,
animation_settings.SetPreemptionStrategy( animation_settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
animation_settings.SetTweenType(gfx::Tween::FAST_OUT_LINEAR_IN); animation_settings.SetTweenType(gfx::Tween::FAST_OUT_LINEAR_IN);
// CleanupWidgetAfterAnimationObserver will delete itself (and the // CleanupAnimationObserver will delete itself (and the widget) when the
// widget) when the movement animation is complete. // motion animation is complete.
animation_settings.AddObserver( // Ownership over the observer is passed to the window_selector_->delegate()
new CleanupWidgetAfterAnimationObserver(std::move(selection_widget_))); // which has longer lifetime so that animations can continue even after the
// overview mode is shut down.
std::unique_ptr<CleanupAnimationObserver> observer(
new CleanupAnimationObserver(std::move(selection_widget_)));
animation_settings.AddObserver(observer.get());
window_selector_->delegate()->AddDelayedAnimationObserver(
std::move(observer));
old_selection->SetOpacity(0.f); old_selection->SetOpacity(0.f);
old_selection_window->SetBounds(old_selection_window->GetBounds() + old_selection_window->SetBounds(old_selection_window->GetBounds() +
fade_out_direction); fade_out_direction);
......
...@@ -55,6 +55,9 @@ class ASH_EXPORT WindowGrid : public WmWindowObserver { ...@@ -55,6 +55,9 @@ class ASH_EXPORT WindowGrid : public WmWindowObserver {
WindowSelector* window_selector); WindowSelector* window_selector);
~WindowGrid() override; ~WindowGrid() override;
// Exits overview mode, fading out the |shield_widget_| if necessary.
void Shutdown();
// Prepares the windows in this grid for overview. This will restore all // Prepares the windows in this grid for overview. This will restore all
// minimized windows and ensure they are visible. // minimized windows and ensure they are visible.
void PrepareForOverview(); void PrepareForOverview();
......
...@@ -398,6 +398,9 @@ void WindowSelector::Shutdown() { ...@@ -398,6 +398,9 @@ void WindowSelector::Shutdown() {
PanelLayoutManager::Get(window)->SetShowCalloutWidgets(true); PanelLayoutManager::Get(window)->SetShowCalloutWidgets(true);
} }
for (std::unique_ptr<WindowGrid>& window_grid : grid_list_)
window_grid->Shutdown();
DCHECK(num_items_ >= remaining_items); DCHECK(num_items_ >= remaining_items);
UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.OverviewClosedItems", UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.OverviewClosedItems",
num_items_ - remaining_items); num_items_ - remaining_items);
......
...@@ -67,6 +67,8 @@ class ASH_EXPORT WindowSelector : public display::DisplayObserver, ...@@ -67,6 +67,8 @@ class ASH_EXPORT WindowSelector : public display::DisplayObserver,
// Called when |window| is about to get closed. // Called when |window| is about to get closed.
void WindowClosing(WindowSelectorItem* window); void WindowClosing(WindowSelectorItem* window);
WindowSelectorDelegate* delegate() { return delegate_; }
bool restoring_minimized_windows() const { bool restoring_minimized_windows() const {
return restoring_minimized_windows_; return restoring_minimized_windows_;
} }
......
...@@ -19,7 +19,14 @@ namespace ash { ...@@ -19,7 +19,14 @@ namespace ash {
WindowSelectorController::WindowSelectorController() {} WindowSelectorController::WindowSelectorController() {}
WindowSelectorController::~WindowSelectorController() {} WindowSelectorController::~WindowSelectorController() {
// Destroy widgets that may be still animating if shell shuts down soon after
// exiting overview mode.
for (std::unique_ptr<DelayedAnimationObserver>& animation_observer :
delayed_animations_) {
animation_observer->Shutdown();
}
}
// static // static
bool WindowSelectorController::CanSelect() { bool WindowSelectorController::CanSelect() {
...@@ -79,6 +86,31 @@ void WindowSelectorController::OnSelectionEnded() { ...@@ -79,6 +86,31 @@ void WindowSelectorController::OnSelectionEnded() {
WmShell::Get()->OnOverviewModeEnded(); WmShell::Get()->OnOverviewModeEnded();
} }
void WindowSelectorController::AddDelayedAnimationObserver(
std::unique_ptr<DelayedAnimationObserver> animation_observer) {
animation_observer->SetOwner(this);
delayed_animations_.push_back(std::move(animation_observer));
}
void WindowSelectorController::RemoveAndDestroyAnimationObserver(
DelayedAnimationObserver* animation_observer) {
class IsEqual {
public:
explicit IsEqual(DelayedAnimationObserver* animation_observer)
: animation_observer_(animation_observer) {}
bool operator()(const std::unique_ptr<DelayedAnimationObserver>& other) {
return (other.get() == animation_observer_);
}
private:
const DelayedAnimationObserver* animation_observer_;
};
delayed_animations_.erase(
std::remove_if(delayed_animations_.begin(), delayed_animations_.end(),
IsEqual(animation_observer)),
delayed_animations_.end());
}
void WindowSelectorController::OnSelectionStarted() { void WindowSelectorController::OnSelectionStarted() {
if (!last_selection_time_.is_null()) { if (!last_selection_time_.is_null()) {
UMA_HISTOGRAM_LONG_TIMES("Ash.WindowSelector.TimeBetweenUse", UMA_HISTOGRAM_LONG_TIMES("Ash.WindowSelector.TimeBetweenUse",
......
...@@ -44,6 +44,10 @@ class ASH_EXPORT WindowSelectorController : public WindowSelectorDelegate { ...@@ -44,6 +44,10 @@ class ASH_EXPORT WindowSelectorController : public WindowSelectorDelegate {
// WindowSelectorDelegate: // WindowSelectorDelegate:
void OnSelectionEnded() override; void OnSelectionEnded() override;
void AddDelayedAnimationObserver(
std::unique_ptr<DelayedAnimationObserver> animation) override;
void RemoveAndDestroyAnimationObserver(
DelayedAnimationObserver* animation) override;
private: private:
friend class WindowSelectorTest; friend class WindowSelectorTest;
...@@ -51,6 +55,11 @@ class ASH_EXPORT WindowSelectorController : public WindowSelectorDelegate { ...@@ -51,6 +55,11 @@ class ASH_EXPORT WindowSelectorController : public WindowSelectorDelegate {
// Dispatched when window selection begins. // Dispatched when window selection begins.
void OnSelectionStarted(); void OnSelectionStarted();
// Collection of DelayedAnimationObserver objects that own widgets that may be
// still animating after overview mode ends. If shell needs to shut down while
// those animations are in progress, the animations are shut down and the
// widgets destroyed.
std::vector<std::unique_ptr<DelayedAnimationObserver>> delayed_animations_;
std::unique_ptr<WindowSelector> window_selector_; std::unique_ptr<WindowSelector> window_selector_;
base::Time last_selection_time_; base::Time last_selection_time_;
......
...@@ -8,18 +8,43 @@ ...@@ -8,18 +8,43 @@
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
namespace aura {
class Window;
}
namespace ash { namespace ash {
class WindowSelectorDelegate;
class ASH_EXPORT DelayedAnimationObserver {
public:
virtual ~DelayedAnimationObserver() {}
// Sets an |owner| that can be notified when the animation that |this|
// observes completes.
virtual void SetOwner(WindowSelectorDelegate* owner) = 0;
// Can be called by the |owner| to delete the owned widget. The |owner| is
// then responsible for deleting |this| instance of the
// DelayedAnimationObserver.
virtual void Shutdown() = 0;
};
// Implement this class to handle the selection event from WindowSelector. // Implement this class to handle the selection event from WindowSelector.
class ASH_EXPORT WindowSelectorDelegate { class ASH_EXPORT WindowSelectorDelegate {
public: public:
// Invoked if selection is ended. // Invoked if selection is ended.
virtual void OnSelectionEnded() = 0; virtual void OnSelectionEnded() = 0;
// Passes ownership of |animation_observer| to |this| delegate.
virtual void AddDelayedAnimationObserver(
std::unique_ptr<DelayedAnimationObserver> animation_observer) = 0;
// Finds and erases |animation_observer| from the list deleting the widget
// owned by the |animation_observer|.
// This method should be called when a scheduled animation completes.
// If the animation completion callback is a result of a window getting
// destroyed then the DelayedAnimationObserver::Shutdown() should be called
// first before destroying the window.
virtual void RemoveAndDestroyAnimationObserver(
DelayedAnimationObserver* animation_observer) = 0;
protected: protected:
virtual ~WindowSelectorDelegate() {} virtual ~WindowSelectorDelegate() {}
}; };
......
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