Commit c2f7861c authored by Kazuki Takise's avatar Kazuki Takise Committed by Commit Bot

Make the window cycle list not activatable.

Taking activation upon long alt-tab can affect the foreground
application, e.g. pausing video.

Note that ChromeVox only works for activated windows, so we leave
the cycler activatable if ChromeVox is on.

Bug: b/138914552
Test: Netflix does not pause when alt-tabbing
Change-Id: Idb5ff6db56f9eaa3141140eacebc2bfea6bc3bab
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1905290Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Commit-Queue: Kazuki Takise <takise@chromium.org>
Auto-Submit: Kazuki Takise <takise@chromium.org>
Cr-Commit-Position: refs/heads/master@{#714784}
parent 412da30c
...@@ -480,9 +480,6 @@ TEST_F(WindowCycleControllerTest, MostRecentlyUsed) { ...@@ -480,9 +480,6 @@ TEST_F(WindowCycleControllerTest, MostRecentlyUsed) {
controller->HandleCycleWindow(WindowCycleController::FORWARD); controller->HandleCycleWindow(WindowCycleController::FORWARD);
EXPECT_FALSE(wm::IsActiveWindow(window0.get())); EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
// Showing the Alt+Tab UI does however deactivate the erstwhile active window.
EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
controller->CompleteCycling(); controller->CompleteCycling();
} }
...@@ -492,6 +489,8 @@ TEST_F(WindowCycleControllerTest, SelectingHidesAppList) { ...@@ -492,6 +489,8 @@ TEST_F(WindowCycleControllerTest, SelectingHidesAppList) {
std::unique_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0)); std::unique_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1)); std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
wm::ActivateWindow(window0.get());
GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplay().id()); GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplay().id());
GetAppListTestHelper()->CheckVisibility(true); GetAppListTestHelper()->CheckVisibility(true);
controller->HandleCycleWindow(WindowCycleController::FORWARD); controller->HandleCycleWindow(WindowCycleController::FORWARD);
...@@ -500,7 +499,7 @@ TEST_F(WindowCycleControllerTest, SelectingHidesAppList) { ...@@ -500,7 +499,7 @@ TEST_F(WindowCycleControllerTest, SelectingHidesAppList) {
// Make sure that dismissing the app list this way doesn't pass activation // Make sure that dismissing the app list this way doesn't pass activation
// to a different window. // to a different window.
EXPECT_FALSE(wm::IsActiveWindow(window0.get())); EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
EXPECT_FALSE(wm::IsActiveWindow(window1.get())); EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
controller->CompleteCycling(); controller->CompleteCycling();
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include "ash/accessibility/accessibility_controller_impl.h"
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h" #include "ash/shell.h"
...@@ -19,7 +21,9 @@ ...@@ -19,7 +21,9 @@
#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_node_data.h"
#include "ui/aura/client/aura_constants.h" #include "ui/aura/client/aura_constants.h"
#include "ui/aura/scoped_window_targeter.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/aura/window_targeter.h"
#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
...@@ -68,6 +72,28 @@ constexpr int kInsideBorderVerticalPaddingDp = 60; ...@@ -68,6 +72,28 @@ constexpr int kInsideBorderVerticalPaddingDp = 60;
// Padding between the window previews within the alt-tab bandshield. // Padding between the window previews within the alt-tab bandshield.
constexpr int kBetweenChildPaddingDp = 10; constexpr int kBetweenChildPaddingDp = 10;
// The alt-tab cycler widget is not activatable (except when ChromeVox is on),
// so we use WindowTargeter to send input events to the widget.
class CustomWindowTargeter : public aura::WindowTargeter {
public:
explicit CustomWindowTargeter(aura::Window* tab_cycler)
: tab_cycler_(tab_cycler) {}
~CustomWindowTargeter() override = default;
// aura::WindowTargeter
ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
ui::Event* event) override {
if (event->IsLocatedEvent())
return aura::WindowTargeter::FindTargetForEvent(root, event);
return tab_cycler_;
}
private:
aura::Window* tab_cycler_;
DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter);
};
} // namespace } // namespace
// This view represents a single aura::Window by displaying a title and a // This view represents a single aura::Window by displaying a title and a
...@@ -338,11 +364,6 @@ WindowCycleList::~WindowCycleList() { ...@@ -338,11 +364,6 @@ WindowCycleList::~WindowCycleList() {
for (auto* window : windows_) for (auto* window : windows_)
window->RemoveObserver(this); window->RemoveObserver(this);
if (!windows_.empty() && user_did_accept_) {
auto* target_window = windows_[current_index_];
SelectWindow(target_window);
}
if (cycle_ui_widget_) if (cycle_ui_widget_)
cycle_ui_widget_->Close(); cycle_ui_widget_->Close();
...@@ -353,6 +374,15 @@ WindowCycleList::~WindowCycleList() { ...@@ -353,6 +374,15 @@ WindowCycleList::~WindowCycleList() {
// crbug.com/681207 // crbug.com/681207
if (cycle_view_) if (cycle_view_)
cycle_view_->DestroyContents(); cycle_view_->DestroyContents();
// While the cycler widget is shown, the windows listed in the cycler is
// marked as force-visible and don't contribute to occlusion. In order to
// work occlusion calculation properly, we need to activate a window after
// the widget has been destroyed. See b/138914552.
if (!windows_.empty() && user_did_accept_) {
auto* target_window = windows_[current_index_];
SelectWindow(target_window);
}
} }
void WindowCycleList::Step(WindowCycleController::Direction direction) { void WindowCycleList::Step(WindowCycleController::Direction direction) {
...@@ -449,11 +479,21 @@ void WindowCycleList::InitWindowCycleView() { ...@@ -449,11 +479,21 @@ void WindowCycleList::InitWindowCycleView() {
cycle_view_ = new WindowCycleView(windows_); cycle_view_ = new WindowCycleView(windows_);
cycle_view_->SetTargetWindow(windows_[current_index_]); cycle_view_->SetTargetWindow(windows_[current_index_]);
// We need to activate the widget if ChromeVox is enabled as ChromeVox relies
// on activation.
const bool spoken_feedback_enabled =
Shell::Get()->accessibility_controller()->spoken_feedback_enabled();
views::Widget* widget = new views::Widget; views::Widget* widget = new views::Widget;
views::Widget::InitParams params; views::Widget::InitParams params;
params.delegate = cycle_view_; params.delegate = cycle_view_;
params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
// Don't let the alt-tab cycler be activatable. This lets the currently
// activated window continue to be in the foreground. This may affect
// things such as video automatically pausing/playing.
if (!spoken_feedback_enabled)
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
params.accept_events = true; params.accept_events = true;
params.name = "WindowCycleList (Alt+Tab)"; params.name = "WindowCycleList (Alt+Tab)";
// TODO(estade): make sure nothing untoward happens when the lock screen // TODO(estade): make sure nothing untoward happens when the lock screen
...@@ -473,6 +513,15 @@ void WindowCycleList::InitWindowCycleView() { ...@@ -473,6 +513,15 @@ void WindowCycleList::InitWindowCycleView() {
screen_observer_.Add(display::Screen::GetScreen()); screen_observer_.Add(display::Screen::GetScreen());
widget->Show(); widget->Show();
cycle_ui_widget_ = widget; cycle_ui_widget_ = widget;
// Since this window is not activated, grab events.
if (!spoken_feedback_enabled) {
window_targeter_ = std::make_unique<aura::ScopedWindowTargeter>(
widget->GetNativeWindow()->GetRootWindow(),
std::make_unique<CustomWindowTargeter>(widget->GetNativeWindow()));
}
// Close the app list, if it's open.
Shell::Get()->app_list_controller()->DismissAppList();
} }
void WindowCycleList::SelectWindow(aura::Window* window) { void WindowCycleList::SelectWindow(aura::Window* window) {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
namespace aura { namespace aura {
class Window; class Window;
class ScopedWindowTargeter;
} }
namespace views { namespace views {
...@@ -109,6 +110,10 @@ class ASH_EXPORT WindowCycleList : public aura::WindowObserver, ...@@ -109,6 +110,10 @@ class ASH_EXPORT WindowCycleList : public aura::WindowObserver,
// A timer to delay showing the UI. Quick Alt+Tab should not flash a UI. // A timer to delay showing the UI. Quick Alt+Tab should not flash a UI.
base::OneShotTimer show_ui_timer_; base::OneShotTimer show_ui_timer_;
// This is needed so that it won't leak keyboard events even if the widget is
// not activatable.
std::unique_ptr<aura::ScopedWindowTargeter> window_targeter_;
DISALLOW_COPY_AND_ASSIGN(WindowCycleList); DISALLOW_COPY_AND_ASSIGN(WindowCycleList);
}; };
......
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