Commit 81e77929 authored by varkha's avatar varkha Committed by Commit bot

[ash-md] Corrects a crash when a window is closed after leaving overview

Exiting overview mode may leave overview header widget still animating.
It is important not to attempt any window manipulation such as
re-stacking when the animation completes because the affected windows
may be gone by then.

BUG=646350
TEST=WindowSelectorTest.SafeToDestroyWindowDuringAnimation

Review-Url: https://codereview.chromium.org/2337383003
Cr-Commit-Position: refs/heads/master@{#418780}
parent 0109afc3
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h" #include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/safe_integer_conversions.h" #include "ui/gfx/geometry/safe_integer_conversions.h"
...@@ -197,7 +198,10 @@ class WindowSelectorItem::RoundedContainerView ...@@ -197,7 +198,10 @@ class WindowSelectorItem::RoundedContainerView
~RoundedContainerView() override { StopObservingLayerAnimations(); } ~RoundedContainerView() override { StopObservingLayerAnimations(); }
void OnItemRestored() { item_ = nullptr; } void OnItemRestored() {
item_ = nullptr;
item_window_ = nullptr;
}
// Starts observing layer animations so that actions can be taken when // Starts observing layer animations so that actions can be taken when
// particular animations (opacity) complete. It should only be called once // particular animations (opacity) complete. It should only be called once
...@@ -216,6 +220,9 @@ class WindowSelectorItem::RoundedContainerView ...@@ -216,6 +220,9 @@ class WindowSelectorItem::RoundedContainerView
layer_ = nullptr; layer_ = nullptr;
} }
// Used by tests to set animation state.
gfx::SlideAnimation* animation() { return animation_.get(); }
void set_color(SkColor target_color) { target_color_ = target_color; } void set_color(SkColor target_color) { target_color_ = target_color; }
// Starts a color animation using |tween_type|. The animation will change the // Starts a color animation using |tween_type|. The animation will change the
...@@ -896,4 +903,8 @@ void WindowSelectorItem::FadeOut(std::unique_ptr<views::Widget> widget) { ...@@ -896,4 +903,8 @@ void WindowSelectorItem::FadeOut(std::unique_ptr<views::Widget> widget) {
widget_ptr->SetOpacity(0.f); widget_ptr->SetOpacity(0.f);
} }
gfx::SlideAnimation* WindowSelectorItem::GetBackgroundViewAnimation() {
return background_view_ ? background_view_->animation() : nullptr;
}
} // namespace ash } // namespace ash
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/button/label_button.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
namespace gfx {
class SlideAnimation;
}
namespace views { namespace views {
class ImageButton; class ImageButton;
} }
...@@ -201,6 +205,9 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener, ...@@ -201,6 +205,9 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
// Fades out a window caption when exiting overview mode. // Fades out a window caption when exiting overview mode.
void FadeOut(std::unique_ptr<views::Widget> widget); void FadeOut(std::unique_ptr<views::Widget> widget);
// Allows a test to directly set animation state.
gfx::SlideAnimation* GetBackgroundViewAnimation();
static bool hide_header() { return use_mask_ || use_shape_; } static bool hide_header() { return use_mask_ || use_shape_; }
// True if the item is being shown in the overview, false if it's being // True if the item is being shown in the overview, false if it's being
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include "ui/display/manager/display_layout.h" #include "ui/display/manager/display_layout.h"
#include "ui/events/event_utils.h" #include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h" #include "ui/events/test/event_generator.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/safe_integer_conversions.h" #include "ui/gfx/geometry/safe_integer_conversions.h"
...@@ -273,6 +274,13 @@ class WindowSelectorTest ...@@ -273,6 +274,13 @@ class WindowSelectorTest
return *iter; return *iter;
} }
gfx::SlideAnimation* GetBackgroundViewAnimationForWindow(
int grid_index,
aura::Window* window) {
return GetWindowItemForWindow(grid_index, window)
->GetBackgroundViewAnimation();
}
// Selects |window| in the active overview session by cycling through all // Selects |window| in the active overview session by cycling through all
// windows in overview until it is found. Returns true if |window| was found, // windows in overview until it is found. Returns true if |window| was found,
// false otherwise. // false otherwise.
...@@ -1286,6 +1294,38 @@ TEST_P(WindowSelectorTest, DISABLED_MinimizedWindowVisibility) { ...@@ -1286,6 +1294,38 @@ TEST_P(WindowSelectorTest, DISABLED_MinimizedWindowVisibility) {
} }
} }
// Tests that it is safe to destroy a window while the overview header animation
// is still active. See http://crbug.com/646350.
TEST_P(WindowSelectorTest, SafeToDestroyWindowDuringAnimation) {
gfx::Rect bounds(0, 0, 400, 400);
{
// Quickly enter and exit overview mode to activate header animations.
std::unique_ptr<aura::Window> window(CreateWindow(bounds));
ui::ScopedAnimationDurationScaleMode test_duration_mode(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
ToggleOverview();
EXPECT_TRUE(IsSelecting());
gfx::SlideAnimation* animation =
GetBackgroundViewAnimationForWindow(0, window.get());
if (ash::MaterialDesignController::IsOverviewMaterial())
ASSERT_NE(nullptr, animation);
ToggleOverview();
EXPECT_FALSE(IsSelecting());
if (animation)
EXPECT_TRUE(animation->is_animating());
// Close the window while the overview header animation is active.
window.reset();
// Progress animation to the end - should not crash.
if (animation) {
animation->SetCurrentValue(1.0);
animation->Reset(1.0);
}
}
}
// Tests that a bounds change during overview is corrected for. // Tests that a bounds change during overview is corrected for.
TEST_P(WindowSelectorTest, BoundsChangeDuringOverview) { TEST_P(WindowSelectorTest, BoundsChangeDuringOverview) {
std::unique_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400))); std::unique_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
......
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