Commit 195aa76f authored by Sammie Quon's avatar Sammie Quon Committed by Commit Bot

overview: Add wallpaper cross fade blur animation.

Keeps this behind a flag, support for old wallpaper blur still exists.
Copies the wallpaper layer to a layer which is blurred and kept alive
for the duration of overview.

Test: manual
Bug: 1012829
Change-Id: I74046bb522d0751304cadd5aa5dd361f70b2831c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1842698Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Commit-Queue: Sammie Quon <sammiequon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#704977}
parent 8faeccfb
......@@ -55,6 +55,9 @@ const base::Feature kNotificationExpansionAnimation{
const base::Feature kNotificationScrollBar{"NotificationScrollBar",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kOverviewCrossFadeWallpaperBlur{
"OverviewCrossFadeWallpaperBlur", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kPipRoundedCorners{"PipRoundedCorners",
base::FEATURE_DISABLED_BY_DEFAULT};
......
......@@ -72,6 +72,10 @@ ASH_PUBLIC_EXPORT extern const base::Feature kNotificationExpansionAnimation;
// Enables notification scroll bar in UnifiedSystemTray.
ASH_PUBLIC_EXPORT extern const base::Feature kNotificationScrollBar;
// Enables using a cross fade animation for the wallpaper blur for overview
// mode.
ASH_PUBLIC_EXPORT extern const base::Feature kOverviewCrossFadeWallpaperBlur;
// Enables rounded corners for the Picture-in-picture window.
ASH_PUBLIC_EXPORT extern const base::Feature kPipRoundedCorners;
......
......@@ -328,7 +328,7 @@ bool OverviewController::HasBlurForTest() const {
}
bool OverviewController::HasBlurAnimationForTest() const {
return overview_wallpaper_controller_->has_blur_animation();
return overview_wallpaper_controller_->HasBlurAnimationForTesting();
}
std::vector<aura::Window*>
......
......@@ -95,6 +95,10 @@ class ASH_EXPORT OverviewController : public OverviewDelegate,
OverviewSession* overview_session() { return overview_session_.get(); }
OverviewWallpaperController* overview_wallpaper_controller() {
return overview_wallpaper_controller_.get();
}
void set_occlusion_pause_duration_for_end_for_test(base::TimeDelta duration) {
occlusion_pause_duration_for_end_ = duration;
}
......
......@@ -8,16 +8,19 @@
#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "ash/keyboard/ui/keyboard_util.h"
#include "ash/keyboard/ui/test/keyboard_test_util.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/keyboard/keyboard_switches.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wallpaper/wallpaper_widget_controller.h"
#include "ash/wm/overview/overview_observer.h"
#include "ash/wm/overview/overview_session.h"
#include "ash/wm/overview/overview_wallpaper_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "ash/wm/window_resizer.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/test/event_generator.h"
......@@ -160,6 +163,9 @@ TEST_F(OverviewControllerTest,
}
TEST_F(OverviewControllerTest, AnimationCallbacks) {
if (base::FeatureList::IsEnabled(features::kOverviewCrossFadeWallpaperBlur))
return;
ui::ScopedAnimationDurationScaleMode non_zero(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
TestOverviewObserver observer(/*should_monitor_animation_state = */ true);
......@@ -236,6 +242,87 @@ TEST_F(OverviewControllerTest, AnimationCallbacks) {
EXPECT_FALSE(overview_controller->HasBlurAnimationForTest());
}
TEST_F(OverviewControllerTest, AnimationCallbacksForCrossFadeWallpaper) {
if (!base::FeatureList::IsEnabled(features::kOverviewCrossFadeWallpaperBlur))
return;
ui::ScopedAnimationDurationScaleMode non_zero(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
TestOverviewObserver observer(/*should_monitor_animation_state = */ true);
// Enter without windows.
auto* overview_controller = Shell::Get()->overview_controller();
overview_controller->StartOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(TestOverviewObserver::COMPLETED,
observer.starting_animation_state());
EXPECT_TRUE(overview_controller->HasBlurForTest());
EXPECT_TRUE(overview_controller->HasBlurAnimationForTest());
overview_controller->overview_wallpaper_controller()
->StopBlurAnimationsForTesting();
// Exiting overview has no animations.
overview_controller->EndOverview();
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.ending_animation_state());
EXPECT_FALSE(overview_controller->HasBlurForTest());
EXPECT_FALSE(overview_controller->HasBlurAnimationForTest());
observer.WaitForEndingAnimationComplete();
EXPECT_EQ(TestOverviewObserver::COMPLETED, observer.ending_animation_state());
EXPECT_FALSE(overview_controller->HasBlurForTest());
EXPECT_FALSE(overview_controller->HasBlurAnimationForTest());
gfx::Rect bounds(0, 0, 100, 100);
std::unique_ptr<aura::Window> window1(
CreateTestWindowInShellWithBounds(bounds));
std::unique_ptr<aura::Window> window2(
CreateTestWindowInShellWithBounds(bounds));
observer.Reset();
ASSERT_EQ(TestOverviewObserver::UNKNOWN, observer.starting_animation_state());
ASSERT_EQ(TestOverviewObserver::UNKNOWN, observer.ending_animation_state());
// Enter with windows.
overview_controller->StartOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.starting_animation_state());
EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.ending_animation_state());
EXPECT_FALSE(overview_controller->HasBlurForTest());
EXPECT_FALSE(overview_controller->HasBlurAnimationForTest());
// Exit with windows before starting animation ends.
overview_controller->EndOverview();
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_EQ(TestOverviewObserver::CANCELED,
observer.starting_animation_state());
EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.ending_animation_state());
// Blur animation never started.
EXPECT_FALSE(overview_controller->HasBlurForTest());
EXPECT_FALSE(overview_controller->HasBlurAnimationForTest());
observer.Reset();
// Enter again before exit animation ends.
overview_controller->StartOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.starting_animation_state());
EXPECT_EQ(TestOverviewObserver::CANCELED, observer.ending_animation_state());
// Blur animation will start when animation is completed.
EXPECT_FALSE(overview_controller->HasBlurForTest());
EXPECT_FALSE(overview_controller->HasBlurAnimationForTest());
observer.Reset();
// Activating window while entering animation should cancel the overview.
wm::ActivateWindow(window1.get());
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_EQ(TestOverviewObserver::CANCELED,
observer.starting_animation_state());
// Blur animation never started.
EXPECT_FALSE(overview_controller->HasBlurForTest());
EXPECT_FALSE(overview_controller->HasBlurAnimationForTest());
}
// Tests the slide animation for overview is never used in clamshell.
TEST_F(OverviewControllerTest, OverviewEnterExitAnimationClamshell) {
TestOverviewObserver observer(/*should_monitor_animation_state = */ false);
......
......@@ -4,6 +4,7 @@
#include "ash/wm/overview/overview_wallpaper_controller.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/wallpaper/wallpaper_controller_impl.h"
......@@ -13,6 +14,11 @@
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_tree_owner.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_util.h"
namespace ash {
......@@ -29,15 +35,31 @@ bool IsWallpaperChangeAllowed() {
Shell::Get()->wallpaper_controller()->IsBlurAllowed();
}
WallpaperWidgetController* GetWallpaperWidgetController(aura::Window* root) {
return RootWindowController::ForWindow(root)->wallpaper_widget_controller();
}
ui::LayerAnimator* GetAnimator(
WallpaperWidgetController* wallpaper_widget_controller) {
return wallpaper_widget_controller->GetWidget()
->GetNativeWindow()
->layer()
->GetAnimator();
}
} // namespace
OverviewWallpaperController::OverviewWallpaperController() = default;
OverviewWallpaperController::OverviewWallpaperController()
: use_cross_fade_(base::FeatureList::IsEnabled(
features::kOverviewCrossFadeWallpaperBlur)) {}
OverviewWallpaperController::~OverviewWallpaperController() {
if (compositor_)
compositor_->RemoveAnimationObserver(this);
for (aura::Window* root : roots_to_animate_)
root->RemoveObserver(this);
StopObservingImplicitAnimations();
}
// static
......@@ -58,6 +80,29 @@ void OverviewWallpaperController::Unblur() {
/*animate_only=*/false);
}
bool OverviewWallpaperController::HasBlurAnimationForTesting() const {
if (!use_cross_fade_)
return !!compositor_;
for (aura::Window* root : Shell::Get()->GetAllRootWindows()) {
auto* wallpaper_widget_controller = GetWallpaperWidgetController(root);
if (GetAnimator(wallpaper_widget_controller)->is_animating())
return true;
}
return false;
}
void OverviewWallpaperController::StopBlurAnimationsForTesting() {
DCHECK(use_cross_fade_);
for (auto& layer_tree : animating_copies_)
layer_tree->root()->GetAnimator()->StopAnimating();
for (aura::Window* root : Shell::Get()->GetAllRootWindows()) {
auto* wallpaper_widget_controller = GetWallpaperWidgetController(root);
wallpaper_widget_controller->EndPendingAnimation();
GetAnimator(wallpaper_widget_controller)->StopAnimating();
}
}
void OverviewWallpaperController::Stop() {
if (compositor_) {
compositor_->RemoveAnimationObserver(this);
......@@ -81,6 +126,7 @@ void OverviewWallpaperController::AnimationProgressed(float value) {
}
void OverviewWallpaperController::OnAnimationStep(base::TimeTicks timestamp) {
DCHECK(!use_cross_fade_);
if (start_time_ == base::TimeTicks()) {
start_time_ = timestamp;
return;
......@@ -98,11 +144,13 @@ void OverviewWallpaperController::OnAnimationStep(base::TimeTicks timestamp) {
void OverviewWallpaperController::OnCompositingShuttingDown(
ui::Compositor* compositor) {
DCHECK(!use_cross_fade_);
if (compositor_ == compositor)
Stop();
}
void OverviewWallpaperController::OnWindowDestroying(aura::Window* window) {
DCHECK(!use_cross_fade_);
window->RemoveObserver(this);
auto it =
std::find(roots_to_animate_.begin(), roots_to_animate_.end(), window);
......@@ -110,6 +158,12 @@ void OverviewWallpaperController::OnWindowDestroying(aura::Window* window) {
roots_to_animate_.erase(it);
}
void OverviewWallpaperController::OnImplicitAnimationsCompleted() {
DCHECK(use_cross_fade_);
animating_copies_.clear();
state_ = WallpaperAnimationState::kNormal;
}
void OverviewWallpaperController::ApplyBlurAndOpacity(aura::Window* root,
int value) {
DCHECK_GE(value, 0);
......@@ -126,6 +180,11 @@ void OverviewWallpaperController::ApplyBlurAndOpacity(aura::Window* root,
void OverviewWallpaperController::OnBlurChange(WallpaperAnimationState state,
bool animate_only) {
if (use_cross_fade_) {
OnBlurChangeCrossFade(state, animate_only);
return;
}
Stop();
for (aura::Window* root : roots_to_animate_)
root->RemoveObserver(this);
......@@ -171,4 +230,88 @@ void OverviewWallpaperController::OnBlurChange(WallpaperAnimationState state,
Start();
}
void OverviewWallpaperController::OnBlurChangeCrossFade(
WallpaperAnimationState state,
bool animate_only) {
state_ = state;
const bool should_blur = state_ == WallpaperAnimationState::kAddingBlur;
if (animate_only)
DCHECK(should_blur);
OverviewSession* overview_session =
Shell::Get()->overview_controller()->overview_session();
for (aura::Window* root : Shell::Get()->GetAllRootWindows()) {
// |overview_session| may be null on overview exit because we call this
// after the animations are done running. We don't support animation on exit
// so just set |should_animate| to false.
OverviewGrid* grid = overview_session
? overview_session->GetGridWithRootWindow(root)
: nullptr;
bool should_animate = grid && grid->ShouldAnimateWallpaper();
if (should_animate != animate_only)
continue;
auto* wallpaper_widget_controller = GetWallpaperWidgetController(root);
wallpaper_widget_controller->EndPendingAnimation();
auto* wallpaper_window =
wallpaper_widget_controller->GetWidget()->GetNativeWindow();
// No need to animate the blur on exiting as this should only be called
// after overview animations are finished.
std::unique_ptr<ui::LayerTreeOwner> copy_layer_tree;
if (should_blur && should_animate) {
// On animating, create the copy that of the wallpaper. The original
// wallpaper layer will then get blurred and faded in. The copy is
// deleted after animating.
copy_layer_tree = ::wm::RecreateLayers(wallpaper_window);
copy_layer_tree->root()->SetOpacity(1.f);
copy_layer_tree->root()->parent()->StackAtBottom(copy_layer_tree->root());
}
ui::Layer* original_layer = wallpaper_window->layer();
original_layer->GetAnimator()->StopAnimating();
original_layer->SetLayerBlur(should_blur ? kWallpaperBlurSigma
: kWallpaperClearBlurSigma);
original_layer->SetOpacity(should_blur ? 0.f : 1.f);
ui::Layer* copy_layer = copy_layer_tree ? copy_layer_tree->root() : nullptr;
if (copy_layer)
copy_layer->GetAnimator()->StopAnimating();
std::unique_ptr<ui::ScopedLayerAnimationSettings> original_settings;
std::unique_ptr<ui::ScopedLayerAnimationSettings> copy_settings;
if (should_blur && should_animate) {
original_settings = std::make_unique<ui::ScopedLayerAnimationSettings>(
original_layer->GetAnimator());
original_settings->SetTransitionDuration(
base::TimeDelta::FromMilliseconds(kBlurSlideDurationMs));
original_settings->SetTweenType(gfx::Tween::EASE_OUT);
DCHECK(copy_layer);
copy_settings = std::make_unique<ui::ScopedLayerAnimationSettings>(
copy_layer->GetAnimator());
copy_settings->SetTransitionDuration(
base::TimeDelta::FromMilliseconds(kBlurSlideDurationMs));
copy_settings->SetTweenType(gfx::Tween::EASE_OUT);
copy_settings->AddObserver(this);
animating_copies_.emplace_back(std::move(copy_layer_tree));
} else {
state_ = WallpaperAnimationState::kNormal;
}
// Tablet mode wallpaper is already dimmed, so no need to change the
// opacity.
float target_opacity =
Shell::Get()->tablet_mode_controller()->InTabletMode() ? 1.f
: kShieldOpacity;
original_layer->SetOpacity(should_blur ? target_opacity : 1.f);
if (copy_layer)
copy_layer->SetOpacity(0.f);
}
if (animating_copies_.empty())
state_ = WallpaperAnimationState::kNormal;
}
} // namespace ash
......@@ -5,13 +5,17 @@
#ifndef ASH_WM_OVERVIEW_OVERVIEW_WALLPAPER_CONTROLLER_H_
#define ASH_WM_OVERVIEW_OVERVIEW_WALLPAPER_CONTROLLER_H_
#include <vector>
#include "ash/ash_export.h"
#include "base/macros.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/compositor_animation_observer.h"
#include "ui/compositor/layer_animation_observer.h"
namespace ui {
class Compositor;
class LayerTreeOwner;
class Window;
} // namespace ui
......@@ -23,7 +27,8 @@ namespace ash {
// animates the blur and dim.
class ASH_EXPORT OverviewWallpaperController
: public ui::CompositorAnimationObserver,
public aura::WindowObserver {
public aura::WindowObserver,
public ui::ImplicitAnimationObserver {
public:
OverviewWallpaperController();
~OverviewWallpaperController() override;
......@@ -35,7 +40,9 @@ class ASH_EXPORT OverviewWallpaperController
void Unblur();
bool has_blur() const { return state_ != WallpaperAnimationState::kNormal; }
bool has_blur_animation() const { return !!compositor_; }
bool HasBlurAnimationForTesting() const;
void StopBlurAnimationsForTesting();
private:
enum class WallpaperAnimationState {
......@@ -55,16 +62,23 @@ class ASH_EXPORT OverviewWallpaperController
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
// ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override;
void ApplyBlurAndOpacity(aura::Window* root, int value);
// Called when the wallpaper is to be changed. Checks to see which root
// windows should have their wallpaper blurs animated and fills
// |roots_to_animate_| accordingly. Applies blur or unblur immediately if
// the wallpaper does not need blur animation.
// When |animate_only| is true, it'll apply blur only to the root windows that
// |roots_to_animate_| or |blur_layers_| accordingly. Applies blur or unblur
// immediately if the wallpaper does not need blur animation. When
// |animate_only| is true, it'll apply blur only to the root windows that
// requires animation.
void OnBlurChange(WallpaperAnimationState state, bool animate_only);
void OnBlurChangeCrossFade(WallpaperAnimationState state, bool animate_only);
const bool use_cross_fade_;
// Used for the compositor animation which drives the normal blur animation.
ui::Compositor* compositor_ = nullptr;
base::TimeTicks start_time_;
......@@ -73,6 +87,10 @@ class ASH_EXPORT OverviewWallpaperController
// blur animated after Blur or Unblur is called.
std::vector<aura::Window*> roots_to_animate_;
// Vector that contains the copied layers, one per root window. This should
// be empty when overview enter animation is not running.
std::vector<std::unique_ptr<ui::LayerTreeOwner>> animating_copies_;
DISALLOW_COPY_AND_ASSIGN(OverviewWallpaperController);
};
......
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