Commit 3033516b authored by Xiaoqian Dai's avatar Xiaoqian Dai Committed by Commit Bot

Tab dragging: background behind the dragged tab's source window.

When dragging a tab out of a browser window (source window), the source
window scales down. The background behind the source window should be
the same blurred and darkened wallpaper as in overview.

See recorded video:
https://drive.google.com/open?id=1I_tXdQzUsiCwAqFikmZi9EywnUG1-wKl

Bug: 874266
Change-Id: Ie25dd3594fbcef37cda5c427e4daebf0ecffb1fd
Reviewed-on: https://chromium-review.googlesource.com/1185521Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Xiaoqian Dai <xdai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585295}
parent 0e509e95
......@@ -64,7 +64,6 @@ constexpr int kOverviewSelectorTransitionMilliseconds = 250;
// The color and opacity of the screen shield in overview.
constexpr SkColor kShieldColor = SkColorSetARGB(255, 0, 0, 0);
constexpr float kShieldOpacity = 0.6f;
// The color and opacity of the overview selector.
constexpr SkColor kWindowSelectionColor = SkColorSetARGB(36, 255, 255, 255);
......@@ -347,6 +346,22 @@ WindowGrid::WindowGrid(aura::Window* root_window,
WindowGrid::~WindowGrid() = default;
// static
SkColor WindowGrid::GetShieldColor() {
SkColor shield_color = kShieldColor;
// Extract the dark muted color from the wallpaper and mix it with
// |kShieldBaseColor|. Just use |kShieldBaseColor| if the dark muted color
// could not be extracted.
SkColor dark_muted_color =
Shell::Get()->wallpaper_controller()->GetProminentColor(
color_utils::ColorProfile());
if (dark_muted_color != ash::kInvalidWallpaperColor) {
shield_color =
color_utils::GetResultingPaintColor(kShieldBaseColor, dark_muted_color);
}
return shield_color;
}
void WindowGrid::Shutdown() {
for (const auto& window : window_list_)
window->Shutdown();
......@@ -1076,17 +1091,6 @@ void WindowGrid::InitShieldWidget() {
SHELF_BACKGROUND_MAXIMIZED)
? 1.f
: 0.f;
SkColor shield_color = kShieldColor;
// Extract the dark muted color from the wallpaper and mix it with
// |kShieldBaseColor|. Just use |kShieldBaseColor| if the dark muted color
// could not be extracted.
SkColor dark_muted_color =
Shell::Get()->wallpaper_controller()->GetProminentColor(
color_utils::ColorProfile());
if (dark_muted_color != ash::kInvalidWallpaperColor) {
shield_color =
color_utils::GetResultingPaintColor(kShieldBaseColor, dark_muted_color);
}
shield_widget_ = CreateBackgroundWidget(
root_window_, ui::LAYER_SOLID_COLOR, SK_ColorTRANSPARENT, 0, 0,
SK_ColorTRANSPARENT, initial_opacity, /*parent=*/nullptr,
......@@ -1098,7 +1102,7 @@ void WindowGrid::InitShieldWidget() {
// Create |shield_view_| and animate its background and label if needed.
shield_view_ = new ShieldView();
shield_view_->SetBackgroundColor(shield_color);
shield_view_->SetBackgroundColor(GetShieldColor());
shield_view_->SetGridBounds(bounds_);
shield_widget_->SetContentsView(shield_view_);
shield_widget_->SetOpacity(initial_opacity);
......
......@@ -58,6 +58,13 @@ class ASH_EXPORT WindowGrid : public aura::WindowObserver,
const gfx::Rect& bounds_in_screen);
~WindowGrid() override;
// The opacity of the shield widget that is used to darden the background of
// the grid.
static constexpr float kShieldOpacity = 0.6f;
// Returns the shield color that is used to darken the background of the grid.
static SkColor GetShieldColor();
// Exits overview mode, fading out the |shield_widget_| if necessary.
void Shutdown();
......
......@@ -38,7 +38,6 @@ namespace {
// when this is true.
bool g_disable_wallpaper_blur_for_tests = false;
constexpr double kWallpaperClearBlurSigma = 0.f;
constexpr int kBlurSlideDurationMs = 250;
// Returns true if |window| should be hidden when entering overview.
......@@ -144,17 +143,17 @@ class WindowSelectorController::OverviewBlurController
if (state_ == WallpaperAnimationState::kNormal)
return;
double value = state_ == WallpaperAnimationState::kAddingBlur
? kWallpaperBlurSigma
: kWallpaperClearBlurSigma;
float value = state_ == WallpaperAnimationState::kAddingBlur
? kWallpaperBlurSigma
: kWallpaperClearBlurSigma;
for (aura::Window* root : roots_to_animate_)
ApplyBlur(root, value);
state_ = WallpaperAnimationState::kNormal;
}
void AnimationProgressed(const gfx::Animation* animation) override {
double value = animation_.CurrentValueBetween(kWallpaperClearBlurSigma,
kWallpaperBlurSigma);
float value = animation_.CurrentValueBetween(kWallpaperClearBlurSigma,
kWallpaperBlurSigma);
for (aura::Window* root : roots_to_animate_)
ApplyBlur(root, value);
}
......@@ -177,7 +176,7 @@ class WindowSelectorController::OverviewBlurController
void ApplyBlur(aura::Window* root, float blur_sigma) {
RootWindowController::ForWindow(root)
->wallpaper_widget_controller()
->SetWallpaperBlur(static_cast<float>(blur_sigma));
->SetWallpaperBlur(blur_sigma);
}
// Called when the wallpaper is to be changed. Checks to see which root
......@@ -186,7 +185,7 @@ class WindowSelectorController::OverviewBlurController
// the wallpaper does not need blur animation.
void OnBlurChange() {
const bool should_blur = state_ == WallpaperAnimationState::kAddingBlur;
const double value =
const float value =
should_blur ? kWallpaperBlurSigma : kWallpaperClearBlurSigma;
for (aura::Window* root : roots_to_animate_)
root->RemoveObserver(this);
......
......@@ -27,7 +27,8 @@ class ASH_EXPORT WindowSelectorController : public WindowSelectorDelegate {
// Amount of blur to apply on the wallpaper when we enter or exit overview
// mode.
static constexpr double kWallpaperBlurSigma = 10.f;
static constexpr float kWallpaperBlurSigma = 10.f;
static constexpr float kWallpaperClearBlurSigma = 0.f;
// Returns true if selecting windows in an overview is enabled. This is false
// at certain times, such as when the lock screen is visible.
......
......@@ -4,6 +4,7 @@
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/display/screen_orientation_controller.h"
#include "ash/display/screen_orientation_controller_test_api.h"
#include "ash/public/cpp/app_types.h"
......@@ -18,6 +19,7 @@
#include "ash/system/status_area_widget.h"
#include "ash/system/status_area_widget_test_helper.h"
#include "ash/test/ash_test_base.h"
#include "ash/wallpaper/wallpaper_controller.h"
#include "ash/wm/drag_window_resizer.h"
#include "ash/wm/drag_window_resizer_mash.h"
#include "ash/wm/mru_window_tracker.h"
......@@ -2549,6 +2551,52 @@ TEST_F(SplitViewTabDraggingTest, DraggedWindowShouldHaveActiveWindowShadow) {
EXPECT_FALSE(shadow_controller->IsShadowVisibleForWindow(window2.get()));
}
// Test that if the source window needs to be scaled up/down because of dragging
// a tab window out of it, other windows' visibilities and the home launcher's
// visibility should change accordingly.
TEST_F(SplitViewTabDraggingTest, SourceWindowBackgroundTest) {
const gfx::Rect bounds(0, 0, 400, 400);
std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
std::unique_ptr<aura::Window> window4(CreateWindow(bounds));
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible());
EXPECT_TRUE(window4->IsVisible());
// 1) Start dragging |window1|. |window2| is the source window.
std::unique_ptr<WindowResizer> resizer =
StartDrag(window1.get(), window2.get());
DragWindowWithOffset(resizer.get(), 10, 10);
// Test that |window3| should be hidden now. |window1| and |window2| should
// stay visible during dragging.
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_FALSE(window3->IsVisible());
EXPECT_FALSE(window4->IsVisible());
// Test that home launcher should be dismissed.
if (Shell::Get()->app_list_controller()->IsHomeLauncherEnabledInTabletMode())
EXPECT_FALSE(Shell::Get()->app_list_controller()->IsVisible());
// Test that during dragging, we could not show a hidden window.
window3->Show();
EXPECT_FALSE(window3->IsVisible());
// After dragging, the windows' visibilities should have restored.
CompleteDrag(std::move(resizer));
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible());
EXPECT_TRUE(window4->IsVisible());
// Test that home launcher should be reshown.
if (Shell::Get()->app_list_controller()->IsHomeLauncherEnabledInTabletMode())
EXPECT_TRUE(Shell::Get()->app_list_controller()->IsVisible());
}
class TestWindowDelegateWithWidget : public views::WidgetDelegate {
public:
TestWindowDelegateWithWidget(bool can_activate)
......
......@@ -4,7 +4,13 @@
#include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h"
#include <vector>
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/wallpaper/wallpaper_widget_controller.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_utils.h"
#include "ash/wm/overview/window_grid.h"
#include "ash/wm/overview/window_selector_controller.h"
......@@ -130,6 +136,141 @@ class SourceWindowAnimationObserver : public ui::ImplicitAnimationObserver,
} // namespace
// WindowsHider hides all visible windows except the currently dragged window
// and the dragged window's source window upon its creation, and restores the
// windows' visibility upon its destruction. It also blurs and darkens the
// background, hides the home launcher if home launcher is enabled. Only need to
// do so if we need to scale up and down the source window when dragging a tab
// window out of it.
class TabletModeBrowserWindowDragDelegate::WindowsHider
: public aura::WindowObserver {
public:
explicit WindowsHider(aura::Window* dragged_window)
: dragged_window_(dragged_window) {
DCHECK(dragged_window);
aura::Window* source_window =
dragged_window->GetProperty(ash::kTabDraggingSourceWindowKey);
DCHECK(source_window);
// Disable the backdrop for |source_window| during dragging.
source_window_backdrop_ = source_window->GetProperty(kBackdropWindowMode);
source_window->SetProperty(kBackdropWindowMode,
BackdropWindowMode::kDisabled);
DCHECK(!Shell::Get()->window_selector_controller()->IsSelecting());
aura::Window* root_window = dragged_window->GetRootWindow();
std::vector<aura::Window*> windows =
Shell::Get()->mru_window_tracker()->BuildMruWindowList();
for (aura::Window* window : windows) {
if (window == dragged_window || window == source_window ||
window->GetRootWindow() != root_window) {
continue;
}
window_visibility_map_.emplace(window, window->IsVisible());
if (window->IsVisible())
window->Hide();
window->AddObserver(this);
}
// Hide the home launcher if it's enabled during dragging.
AppListControllerImpl* app_list_controller =
Shell::Get()->app_list_controller();
if (app_list_controller->IsHomeLauncherEnabledInTabletMode())
app_list_controller->DismissAppList();
// Blurs the wallpaper background.
RootWindowController::ForWindow(root_window)
->wallpaper_widget_controller()
->SetWallpaperBlur(
static_cast<float>(WindowSelectorController::kWallpaperBlurSigma));
// Darken the background.
shield_widget_ = CreateBackgroundWidget(
root_window, ui::LAYER_SOLID_COLOR, SK_ColorTRANSPARENT, 0, 0,
SK_ColorTRANSPARENT, /*initial_opacity*/ 1.f, /*parent=*/nullptr,
/*stack_on_top=*/true);
aura::Window* widget_window = shield_widget_->GetNativeWindow();
const gfx::Rect bounds = widget_window->parent()->bounds();
widget_window->SetBounds(bounds);
views::View* shield_view = new views::View();
shield_view->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
shield_view->layer()->SetColor(WindowGrid::GetShieldColor());
shield_view->layer()->SetOpacity(WindowGrid::kShieldOpacity);
shield_widget_->SetContentsView(shield_view);
}
~WindowsHider() override {
// It might be possible that |source_window| is destroyed during dragging.
aura::Window* source_window =
dragged_window_->GetProperty(ash::kTabDraggingSourceWindowKey);
if (source_window)
source_window->SetProperty(kBackdropWindowMode, source_window_backdrop_);
for (auto iter = window_visibility_map_.begin();
iter != window_visibility_map_.end(); ++iter) {
iter->first->RemoveObserver(this);
if (iter->second)
iter->first->Show();
}
DCHECK(!Shell::Get()->window_selector_controller()->IsSelecting());
// Reshow the home launcher if it's enabled after dragging.
AppListControllerImpl* app_list_controller =
Shell::Get()->app_list_controller();
if (app_list_controller->IsHomeLauncherEnabledInTabletMode())
app_list_controller->ShowAppList();
// Clears the background wallpaper blur.
RootWindowController::ForWindow(dragged_window_->GetRootWindow())
->wallpaper_widget_controller()
->SetWallpaperBlur(WindowSelectorController::kWallpaperClearBlurSigma);
// Clears the background darken widget.
shield_widget_.reset();
}
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override {
window->RemoveObserver(this);
window_visibility_map_.erase(window);
}
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
if (visible) {
// Do not let |window| change to visible during the lifetime of |this|.
// Also update |window_visibility_map_| so that we can restore the window
// visibility correctly.
window->Hide();
window_visibility_map_[window] = visible;
}
// else do nothing. It must come from Hide() function above thus should be
// ignored.
}
private:
// The currently dragged window. Guaranteed to be non-nullptr during the
// lifetime of |this|.
aura::Window* dragged_window_;
// A shield that darkens the entire background during dragging. It should
// have the same effect as in overview.
std::unique_ptr<views::Widget> shield_widget_;
// Maintains the map between windows and their visibilities. All windows
// except the dragged window and the source window should stay hidden during
// dragging.
std::map<aura::Window*, bool> window_visibility_map_;
// The original backdrop mode of the source window. Should be disabled during
// dragging.
BackdropWindowMode source_window_backdrop_ = BackdropWindowMode::kAuto;
DISALLOW_COPY_AND_ASSIGN(WindowsHider);
};
TabletModeBrowserWindowDragDelegate::TabletModeBrowserWindowDragDelegate() =
default;
......@@ -172,6 +313,7 @@ void TabletModeBrowserWindowDragDelegate::EndingForDraggedWindow(
wm::GetWindowState(source_window));
}
scrim_.reset();
windows_hider_.reset();
}
bool TabletModeBrowserWindowDragDelegate::ShouldOpenOverviewWhenDragStarts() {
......@@ -196,6 +338,10 @@ void TabletModeBrowserWindowDragDelegate::UpdateSourceWindow(
return;
}
// Only create WindowHider if we need to scale up/down the source window.
if (!windows_hider_)
windows_hider_ = std::make_unique<WindowsHider>(dragged_window_);
const gfx::Rect work_area_bounds =
display::Screen::GetScreen()
->GetDisplayNearestWindow(dragged_window_)
......
......@@ -24,6 +24,8 @@ class TabletModeBrowserWindowDragDelegate
~TabletModeBrowserWindowDragDelegate() override;
private:
class WindowsHider;
// TabletModeWindowDragDelegate:
void PrepareForDraggedWindow(const gfx::Point& location_in_screen) override;
void UpdateForDraggedWindow(const gfx::Point& location_in_screen) override;
......@@ -50,6 +52,13 @@ class TabletModeBrowserWindowDragDelegate
// browser window beneath it during dragging.
std::unique_ptr<views::Widget> scrim_;
// It's used to hide all visible windows if the source window needs to be
// scaled up/down during dragging a tab out of the source window. It also
// hides the home launcher if home launcher is enabled, blurs and darkens the
// background upon its creation. All of these will be restored upon its
// destruction.
std::unique_ptr<WindowsHider> windows_hider_;
DISALLOW_COPY_AND_ASSIGN(TabletModeBrowserWindowDragDelegate);
};
......
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