blob: a2e1f9563c88a8dc2db27cc5d4359843e59e4f3a [file] [log] [blame]
// Copyright (c) 2012 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/system/tray/system_tray.h"
#include <memory>
#include <string>
#include <vector>
#include "ash/accelerators/accelerator_controller.h"
#include "ash/accessibility/accessibility_delegate.h"
#include "ash/ash_view_ids.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/root_window_controller.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/status_area_widget_test_helper.h"
#include "ash/system/tray/system_tray_bubble.h"
#include "ash/system/tray/system_tray_item.h"
#include "ash/system/tray/test_system_tray_item.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray_drag_controller.h"
#include "ash/system/web_notification/web_notification_tray.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_helper.h"
#include "ash/test/ash_test_views_delegate.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/window_util.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "ui/app_list/presenter/app_list.h"
#include "ui/app_list/presenter/test/test_app_list_presenter.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/controls/separator.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace ash {
namespace {
const char kVisibleRowsHistogramName[] =
"Ash.SystemMenu.DefaultView.VisibleRows";
class ModalWidgetDelegate : public views::WidgetDelegateView {
public:
ModalWidgetDelegate() = default;
~ModalWidgetDelegate() override = default;
ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_SYSTEM; }
private:
DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
};
class KeyEventConsumerView : public views::View {
public:
KeyEventConsumerView() : number_of_consumed_key_events_(0) {
SetFocusBehavior(FocusBehavior::ALWAYS);
}
~KeyEventConsumerView() override = default;
// Overriden from views::View
bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override {
return true;
}
void OnKeyEvent(ui::KeyEvent* key_event) override {
number_of_consumed_key_events_++;
}
int number_of_consumed_key_events() { return number_of_consumed_key_events_; }
private:
int number_of_consumed_key_events_;
DISALLOW_COPY_AND_ASSIGN(KeyEventConsumerView);
};
} // namespace
// TODO(minch): move swiping related tests from SystemTrayTest to
// TraybackgroundView / TrayDragController. crbug.com/745073
class SystemTrayTest : public AshTestBase {
public:
SystemTrayTest() = default;
~SystemTrayTest() override = default;
// Swiping on the system tray and ends with finger released. Note, |start| is
// based on the system tray or system tray bubble's coordinate space.
void SendGestureEvent(gfx::Point& start,
float delta,
bool is_fling,
float velocity_y,
float scroll_y_hint = -1.0f,
bool drag_on_bubble = false) {
base::TimeTicks timestamp = base::TimeTicks::Now();
SendScrollStartAndUpdate(start, delta, timestamp, scroll_y_hint,
drag_on_bubble);
ui::GestureEventDetails details =
is_fling
? ui::GestureEventDetails(ui::ET_SCROLL_FLING_START, 0, velocity_y)
: ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END);
ui::GestureEvent event = ui::GestureEvent(start.x(), start.y() + delta,
ui::EF_NONE, timestamp, details);
DispatchGestureEvent(&event, drag_on_bubble);
}
// Swiping on the system tray without releasing the finger.
void SendScrollStartAndUpdate(gfx::Point& start,
float delta,
base::TimeTicks& timestamp,
float scroll_y_hint = -1.0f,
bool drag_on_bubble = false) {
ui::GestureEventDetails begin_details(ui::ET_GESTURE_SCROLL_BEGIN, 0,
scroll_y_hint);
ui::GestureEvent begin_event = ui::GestureEvent(
start.x(), start.y(), ui::EF_NONE, timestamp, begin_details);
DispatchGestureEvent(&begin_event, drag_on_bubble);
ui::GestureEventDetails update_details(ui::ET_GESTURE_SCROLL_UPDATE, 0,
delta);
timestamp += base::TimeDelta::FromMilliseconds(100);
ui::GestureEvent update_event = ui::GestureEvent(
start.x(), start.y() + delta, ui::EF_NONE, timestamp, update_details);
DispatchGestureEvent(&update_event, drag_on_bubble);
}
// Dispatches |event| to target according to |drag_on_bubble|.
void DispatchGestureEvent(ui::GestureEvent* event, bool drag_on_bubble) {
SystemTray* system_tray = GetPrimarySystemTray();
views::View* target = drag_on_bubble
? system_tray->GetSystemBubble()->bubble_view()
: static_cast<views::View*>(system_tray);
ui::Event::DispatcherApi(event).set_target(target);
target->OnGestureEvent(event);
}
// Open the default system tray bubble to get the height of the bubble and
// then close it.
float GetSystemBubbleHeight() {
SystemTray* system_tray = GetPrimarySystemTray();
system_tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
gfx::Rect bounds = GetSystemBubbleBoundsInScreen();
system_tray->CloseBubble();
return bounds.height();
}
gfx::Rect GetSystemBubbleBoundsInScreen() {
return GetPrimarySystemTray()
->GetSystemBubble()
->bubble_view()
->GetWidget()
->GetWindowBoundsInScreen();
}
private:
DISALLOW_COPY_AND_ASSIGN(SystemTrayTest);
};
// TODO(minch): Swiping the status area tray or associated bubble in tablet mode
// has been disabled currently, it may be added back in the future.
// http://crbug.com/767679.
// Swiping on the overlap area of shelf and system tray bubble during the
// animation should close the bubble.
TEST_F(SystemTrayTest, DISABLED_SwipingOnShelfDuringAnimation) {
Shelf* shelf = GetPrimaryShelf();
SystemTray* system_tray = GetPrimarySystemTray();
gfx::Point start = system_tray->GetLocalBounds().CenterPoint();
EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
gfx::Rect shelf_bounds_in_screen =
shelf->shelf_widget()->GetWindowBoundsInScreen();
system_tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
gfx::Rect original_bounds = GetSystemBubbleBoundsInScreen();
system_tray->CloseBubble();
// Enable animations so that we can make sure that they occur.
ui::ScopedAnimationDurationScaleMode regular_animations(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
ui::test::EventGenerator& generator = GetEventGenerator();
gfx::Point point_on_shelf_start =
gfx::Point(original_bounds.x() + 5, shelf_bounds_in_screen.y() + 5);
gfx::Point point_on_shelf_end(point_on_shelf_start.x(),
shelf_bounds_in_screen.bottom());
// Swiping up exceed one third of the height of the bubble should show the
// bubble.
float delta = -original_bounds.height() / 2;
SendGestureEvent(start, delta, false, 0);
EXPECT_TRUE(system_tray->HasSystemBubble());
gfx::Rect current_bounds = GetSystemBubbleBoundsInScreen();
// Dragging the shelf during up animation should close the bubble.
if (current_bounds.y() != original_bounds.y()) {
generator.GestureScrollSequence(point_on_shelf_start, point_on_shelf_end,
base::TimeDelta::FromMilliseconds(100), 5);
EXPECT_FALSE(system_tray->HasSystemBubble());
}
// Fling down on the shelf with a velocity that exceeds |kFlingVelocity|.
EXPECT_FALSE(system_tray->HasSystemBubble());
SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity + 1);
current_bounds = GetSystemBubbleBoundsInScreen();
EXPECT_TRUE(system_tray->HasSystemBubble());
// Dragging the shelf during down animation should close the bubble.
if (current_bounds.y() != original_bounds.y()) {
generator.GestureScrollSequence(point_on_shelf_start, point_on_shelf_end,
base::TimeDelta::FromMilliseconds(100), 5);
EXPECT_FALSE(system_tray->HasSystemBubble());
}
}
// TODO(minch): Swiping the status area tray or associated bubble in tablet mode
// has been disabled currently, it may be added back in the future.
// http://crbug.com/767679.
// Swiping on the system tray ends with fling event.
TEST_F(SystemTrayTest, DISABLED_FlingOnSystemTray) {
Shelf* shelf = GetPrimaryShelf();
SystemTray* system_tray = GetPrimarySystemTray();
gfx::Point start = system_tray->GetLocalBounds().CenterPoint();
EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
// Fling up on the system tray should show the bubble if the |velocity_y| is
// larger than |kFlingVelocity| and the dragging amount is larger than one
// third of the height of the bubble.
float delta = -GetSystemBubbleHeight();
SendGestureEvent(start, delta, true,
-(TrayDragController::kFlingVelocity + 1));
EXPECT_TRUE(system_tray->HasSystemBubble());
system_tray->CloseBubble();
// Fling up on the system tray should show the bubble if the |velocity_y| is
// larger than |kFlingVelocity| even the dragging amount is less than one
// third of the height of the bubble.
delta /= 4;
SendGestureEvent(start, delta, true,
-(TrayDragController::kFlingVelocity + 1));
EXPECT_TRUE(system_tray->HasSystemBubble());
system_tray->CloseBubble();
// Fling up on the system tray should show the bubble if the |velocity_y| is
// less than |kFlingVelocity| but the dragging amount if larger than one third
// of the height of the bubble.
delta = -GetSystemBubbleHeight();
SendGestureEvent(start, delta, true,
-(TrayDragController::kFlingVelocity - 1));
EXPECT_TRUE(system_tray->HasSystemBubble());
system_tray->CloseBubble();
// Fling up on the system tray should close the bubble if the |velocity_y|
// is less than |kFlingVelocity| and the dragging amount is less than one
// third of the height of the bubble.
delta /= 4;
SendGestureEvent(start, delta, true,
-(TrayDragController::kFlingVelocity - 1));
EXPECT_FALSE(system_tray->HasSystemBubble());
// Fling down on the system tray should close the bubble if the |velocity_y|
// is larger than kFLingVelocity.
SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity + 1);
EXPECT_FALSE(system_tray->HasSystemBubble());
// Fling down on the system tray should close the bubble if the |velocity_y|
// is larger than |kFlingVelocity| even the dragging amount is larger than one
// third of the height of the bubble.
delta = -GetSystemBubbleHeight();
SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity + 1);
EXPECT_FALSE(system_tray->HasSystemBubble());
// Fling down on the system tray should open the bubble if the |velocity_y| is
// less than |kFlingVelocity| but the dragging amount exceed one third of the
// height of the bubble.
SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity - 1);
EXPECT_TRUE(system_tray->HasSystemBubble());
system_tray->CloseBubble();
// Fling down on the system tray should close the bubble if the |velocity_y|
// is less than |kFlingVelocity| and the dragging amount is less than one
// third of the height of the bubble.
delta /= 4;
SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity - 1);
EXPECT_FALSE(system_tray->HasSystemBubble());
}
// TODO(minch): Swiping the status area tray or associated bubble in tablet mode
// has been disabled currently, it may be added back in the future.
// http://crbug.com/767679.
// Touch outside the system tray bubble during swiping should close the bubble.
TEST_F(SystemTrayTest, DISABLED_TapOutsideCloseBubble) {
Shelf* shelf = GetPrimaryShelf();
SystemTray* system_tray = GetPrimarySystemTray();
gfx::Point start = system_tray->GetLocalBounds().CenterPoint();
EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
float delta = -GetSystemBubbleHeight();
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
base::TimeTicks timestamp = base::TimeTicks::Now();
SendScrollStartAndUpdate(start, delta, timestamp);
EXPECT_TRUE(system_tray->HasSystemBubble());
ui::test::EventGenerator& generator = GetEventGenerator();
gfx::Rect bounds = GetSystemBubbleBoundsInScreen();
gfx::Point point_outside = gfx::Point(bounds.x() - 5, bounds.y() - 5);
generator.GestureTapAt(point_outside);
EXPECT_FALSE(system_tray->HasSystemBubble());
}
// TODO(minch): Swiping the status area tray or associated bubble in tablet mode
// has been disabled currently, it may be added back in the future.
// http://crbug.com/767679.
// Swiping on the system tray ends with scroll event.
TEST_F(SystemTrayTest, DISABLED_SwipingOnSystemTray) {
Shelf* shelf = GetPrimaryShelf();
SystemTray* system_tray = GetPrimarySystemTray();
gfx::Point start = system_tray->GetLocalBounds().CenterPoint();
EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
// Swiping up on the system tray has no effect if it is not in tablet mode.
float delta = -GetSystemBubbleHeight();
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
EXPECT_FALSE(system_tray->HasSystemBubble());
SendGestureEvent(start, delta, false, 0);
EXPECT_FALSE(system_tray->HasSystemBubble());
// Swiping up on the system tray should show the system tray bubble if it is
// in tablet mode.
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
SendGestureEvent(start, delta, false, 0);
EXPECT_TRUE(system_tray->HasSystemBubble());
system_tray->CloseBubble();
// Swiping up less than one third of the bubble's height should not show the
// bubble.
delta /= 4;
SendGestureEvent(start, delta, false, 0);
EXPECT_FALSE(system_tray->HasSystemBubble());
// Swiping up more than one third of the bubble's height should show the
// bubble.
delta = -GetSystemBubbleHeight() / 2;
SendGestureEvent(start, delta, false, 0);
EXPECT_TRUE(system_tray->HasSystemBubble());
system_tray->CloseBubble();
// Swiping up on system tray should not show the system tray bubble if the
// shelf is left alignment.
delta = -GetSystemBubbleHeight();
shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
SendGestureEvent(start, delta, false, 0);
EXPECT_FALSE(system_tray->HasSystemBubble());
// Swiping up on system tray should not show the system tray bubble if the
// shelf is right alignment.
shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
SendGestureEvent(start, delta, false, 0);
EXPECT_FALSE(system_tray->HasSystemBubble());
// Beginning to scroll downward on the shelf should not show the system tray
// bubble, even if the drag then moves upwards.
shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
SendGestureEvent(start, delta, false, 0, 1);
EXPECT_FALSE(system_tray->HasSystemBubble());
}
// TODO(minch): Swiping the status area tray or associated bubble in tablet mode
// has been disabled currently, it may be added back in the future.
// http://crbug.com/767679.
// Tests for swiping down on an open system tray bubble in order to
// close it.
TEST_F(SystemTrayTest, DISABLED_SwipingOnSystemTrayBubble) {
Shelf* shelf = GetPrimaryShelf();
SystemTray* system_tray = GetPrimarySystemTray();
EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
// Beginning to scroll downward and then swiping down more than one third of
// the bubble's height should close the bubble. This only takes effect in
// maximize mode.
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
system_tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
gfx::Rect bounds =
system_tray->GetSystemBubble()->bubble_view()->GetLocalBounds();
float delta = bounds.height() / 2;
gfx::Point start(bounds.x() + 5, bounds.y() + 5);
SendGestureEvent(start, delta, false, 0, 1, true);
EXPECT_FALSE(system_tray->HasSystemBubble());
// Beginning to scroll upward and then swiping down more than one third of the
// bubble's height should also close the bubble.
system_tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
SendGestureEvent(start, delta, false, 0, -1, true);
EXPECT_FALSE(system_tray->HasSystemBubble());
// Swiping on the bubble has no effect if it is not in maximize mode.
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
system_tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
SendGestureEvent(start, delta, false, 0, -1, true);
EXPECT_TRUE(system_tray->HasSystemBubble());
}
// Tests that press the search key can toggle the launcher when all the windows
// are minimized after open the system tray bubble in tablet mode.
TEST_F(SystemTrayTest, ToggleAppListAfterOpenSystemTrayBubbleInTabletMode) {
EXPECT_FALSE(wm::GetActiveWindow());
SystemTray* system_tray = GetPrimarySystemTray();
// Open the system tray bubble in tablet mode.
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
EXPECT_FALSE(system_tray->clipping_window_for_test());
system_tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
ASSERT_FALSE(system_tray->drag_controller());
EXPECT_FALSE(system_tray->clipping_window_for_test());
app_list::test::TestAppListPresenter test_app_list_presenter;
Shell::Get()->app_list()->SetAppListPresenter(
test_app_list_presenter.CreateInterfacePtrAndBind());
// Convert from tablet mode to clamshell.
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
EXPECT_EQ(0u, test_app_list_presenter.toggle_count());
// Press the search key should toggle the launcher.
ui::test::EventGenerator& generator = GetEventGenerator();
generator.PressKey(ui::VKEY_BROWSER_SEARCH, ui::EF_NONE);
RunAllPendingInMessageLoop();
EXPECT_EQ(1u, test_app_list_presenter.toggle_count());
// Press the search key again should still toggle the launcher.
generator.PressKey(ui::VKEY_BROWSER_SEARCH, ui::EF_NONE);
RunAllPendingInMessageLoop();
EXPECT_EQ(2u, test_app_list_presenter.toggle_count());
}
// Verifies only the visible default views are recorded in the
// "Ash.SystemMenu.DefaultView.VisibleItems" histogram.
TEST_F(SystemTrayTest, OnlyVisibleItemsRecorded) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
TestSystemTrayItem* test_item = new TestSystemTrayItem();
tray->AddTrayItem(base::WrapUnique(test_item));
base::HistogramTester histogram_tester;
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName,
SystemTrayItem::UMA_TEST, 1);
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName,
SystemTrayItem::UMA_TEST, 2);
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
test_item->set_views_are_visible(false);
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName,
SystemTrayItem::UMA_TEST, 2);
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
}
// Verifies a visible UMA_NOT_RECORDED default view is not recorded in the
// "Ash.SystemMenu.DefaultView.VisibleItems" histogram.
TEST_F(SystemTrayTest, NotRecordedtemsAreNotRecorded) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
tray->AddTrayItem(
std::make_unique<TestSystemTrayItem>(SystemTrayItem::UMA_NOT_RECORDED));
base::HistogramTester histogram_tester;
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName,
SystemTrayItem::UMA_NOT_RECORDED, 0);
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
}
// Verifies null default views are not recorded in the
// "Ash.SystemMenu.DefaultView.VisibleItems" histogram.
TEST_F(SystemTrayTest, NullDefaultViewIsNotRecorded) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
auto test_item = std::make_unique<TestSystemTrayItem>();
test_item->set_has_views(false);
tray->AddTrayItem(std::move(test_item));
base::HistogramTester histogram_tester;
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName,
SystemTrayItem::UMA_TEST, 0);
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
}
// Verifies visible detailed views are not recorded in the
// "Ash.SystemMenu.DefaultView.VisibleItems" histogram.
TEST_F(SystemTrayTest, VisibleDetailedViewsIsNotRecorded) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
TestSystemTrayItem* test_item = new TestSystemTrayItem();
tray->AddTrayItem(base::WrapUnique(test_item));
base::HistogramTester histogram_tester;
tray->ShowDetailedView(test_item, 0, BUBBLE_CREATE_NEW);
RunAllPendingInMessageLoop();
histogram_tester.ExpectTotalCount(kVisibleRowsHistogramName, 0);
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
}
// Verifies visible default views are not recorded for menu re-shows in the
// "Ash.SystemMenu.DefaultView.VisibleItems" histogram.
TEST_F(SystemTrayTest, VisibleDefaultViewIsNotRecordedOnReshow) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
TestSystemTrayItem* test_item = new TestSystemTrayItem();
tray->AddTrayItem(base::WrapUnique(test_item));
base::HistogramTester histogram_tester;
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName,
SystemTrayItem::UMA_TEST, 1);
tray->ShowDetailedView(test_item, 0, BUBBLE_USE_EXISTING);
RunAllPendingInMessageLoop();
histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName,
SystemTrayItem::UMA_TEST, 1);
tray->ShowDefaultView(BUBBLE_USE_EXISTING, false /* show_by_click */);
RunAllPendingInMessageLoop();
histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName,
SystemTrayItem::UMA_TEST, 1);
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
}
TEST_F(SystemTrayTest, SystemTrayDefaultView) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
// Ensure that closing the bubble destroys it.
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
ASSERT_FALSE(tray->HasSystemBubble());
}
// Make sure the opening system tray bubble will not deactivate the
// other window. crbug.com/120680.
TEST_F(SystemTrayTest, Activation) {
SystemTray* tray = GetPrimarySystemTray();
std::unique_ptr<views::Widget> widget(CreateTestWidget(
nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100)));
EXPECT_TRUE(widget->IsActive());
// The window stays active after the bubble opens.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
ASSERT_TRUE(tray->GetWidget());
EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
EXPECT_TRUE(widget->IsActive());
// Activating the bubble makes the window lose activation.
tray->ActivateBubble();
EXPECT_TRUE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
EXPECT_FALSE(widget->IsActive());
// Closing the bubble re-activates the window.
tray->CloseBubble();
EXPECT_TRUE(widget->IsActive());
// Opening the bubble with an accelerator activates the bubble because the
// user will probably navigate with the keyboard.
Shell::Get()->accelerator_controller()->PerformActionIfEnabled(
TOGGLE_SYSTEM_TRAY_BUBBLE);
ASSERT_TRUE(tray->GetWidget());
EXPECT_TRUE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
EXPECT_FALSE(widget->IsActive());
}
// Makes sure that the system tray bubble closes when another window is
// activated, and does not crash regardless of the initial activation state.
// Regression test for crbug.com/704432 .
TEST_F(SystemTrayTest, CloseOnActivation) {
SystemTray* tray = GetPrimarySystemTray();
// Show the system bubble.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
// Test 1: no crash when there's no active window to begin with.
EXPECT_FALSE(wm::GetActiveWindow());
// Showing a new window and activating it will close the system bubble.
std::unique_ptr<views::Widget> widget(CreateTestWidget(
nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100)));
EXPECT_TRUE(widget->IsActive());
EXPECT_FALSE(tray->GetSystemBubble());
// Show a second widget.
std::unique_ptr<views::Widget> second_widget(CreateTestWidget(
nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100)));
EXPECT_TRUE(second_widget->IsActive());
// Re-show the system bubble.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
// Test 2: also no crash when there is a previously active window.
EXPECT_TRUE(wm::GetActiveWindow());
// Re-activate the first widget. The system bubble should hide again.
widget->Activate();
EXPECT_FALSE(tray->GetSystemBubble());
}
// Opening and closing the bubble should change the coloring of the tray.
TEST_F(SystemTrayTest, SystemTrayColoring) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
// At the beginning the tray coloring is not active.
ASSERT_FALSE(tray->is_active());
// Showing the system bubble should show the background as active.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
ASSERT_TRUE(tray->is_active());
// Closing the system menu should change the coloring back to normal.
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
ASSERT_FALSE(tray->is_active());
}
// Closing the system bubble through an alignment change should change the
// system tray coloring back to normal.
TEST_F(SystemTrayTest, SystemTrayColoringAfterAlignmentChange) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
Shelf* shelf = GetPrimaryShelf();
shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
// At the beginning the tray coloring is not active.
ASSERT_FALSE(tray->is_active());
// Showing the system bubble should show the background as active.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
ASSERT_TRUE(tray->is_active());
// Changing the alignment should close the system bubble and change the
// background color.
shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
ASSERT_FALSE(tray->is_active());
RunAllPendingInMessageLoop();
// The bubble should already be closed by now.
ASSERT_FALSE(tray->HasSystemBubble());
}
TEST_F(SystemTrayTest, SystemTrayTestItems) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
TestSystemTrayItem* test_item = new TestSystemTrayItem();
TestSystemTrayItem* detailed_item = new TestSystemTrayItem();
tray->AddTrayItem(base::WrapUnique(test_item));
tray->AddTrayItem(base::WrapUnique(detailed_item));
// Check items have been added.
std::vector<SystemTrayItem*> items = tray->GetTrayItems();
ASSERT_TRUE(std::find(items.begin(), items.end(), test_item) != items.end());
ASSERT_TRUE(std::find(items.begin(), items.end(), detailed_item) !=
items.end());
// Ensure the tray views are created.
ASSERT_TRUE(test_item->tray_view() != NULL);
ASSERT_TRUE(detailed_item->tray_view() != NULL);
// Ensure a default views are created.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
ASSERT_TRUE(test_item->default_view() != NULL);
ASSERT_TRUE(detailed_item->default_view() != NULL);
// Show the detailed view, ensure it's created and the default view destroyed.
tray->ShowDetailedView(detailed_item, 0, BUBBLE_CREATE_NEW);
RunAllPendingInMessageLoop();
ASSERT_TRUE(test_item->default_view() == NULL);
ASSERT_TRUE(detailed_item->detailed_view() != NULL);
// Show the default view, ensure it's created and the detailed view destroyed.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
ASSERT_TRUE(test_item->default_view() != NULL);
ASSERT_TRUE(detailed_item->detailed_view() == NULL);
}
TEST_F(SystemTrayTest, SystemTrayNoViewItems) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
// Verify that no crashes occur on items lacking some views.
TestSystemTrayItem* no_view_item = new TestSystemTrayItem();
no_view_item->set_has_views(false);
tray->AddTrayItem(base::WrapUnique(no_view_item));
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
tray->ShowDetailedView(no_view_item, 0, BUBBLE_USE_EXISTING);
RunAllPendingInMessageLoop();
}
TEST_F(SystemTrayTest, TrayWidgetAutoResizes) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
// Add an initial tray item so that the tray gets laid out correctly.
TestSystemTrayItem* initial_item = new TestSystemTrayItem();
tray->AddTrayItem(base::WrapUnique(initial_item));
gfx::Size initial_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
TestSystemTrayItem* new_item = new TestSystemTrayItem();
tray->AddTrayItem(base::WrapUnique(new_item));
gfx::Size new_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
// Adding the new item should change the size of the tray.
EXPECT_NE(initial_size.ToString(), new_size.ToString());
// Hiding the tray view of the new item should also change the size of the
// tray.
new_item->tray_view()->SetVisible(false);
EXPECT_EQ(initial_size.ToString(),
tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
new_item->tray_view()->SetVisible(true);
EXPECT_EQ(new_size.ToString(),
tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
}
// Test is flaky. http://crbug.com/637978
TEST_F(SystemTrayTest, DISABLED_BubbleCreationTypesTest) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
TestSystemTrayItem* test_item = new TestSystemTrayItem();
tray->AddTrayItem(base::WrapUnique(test_item));
// Ensure the tray views are created.
ASSERT_TRUE(test_item->tray_view() != NULL);
// Show the default view, ensure the notification view is destroyed.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
views::Widget* widget = test_item->default_view()->GetWidget();
gfx::Rect bubble_bounds = widget->GetWindowBoundsInScreen();
tray->ShowDetailedView(test_item, 0, BUBBLE_USE_EXISTING);
RunAllPendingInMessageLoop();
EXPECT_FALSE(test_item->default_view());
EXPECT_EQ(bubble_bounds.ToString(), test_item->detailed_view()
->GetWidget()
->GetWindowBoundsInScreen()
.ToString());
EXPECT_EQ(widget, test_item->detailed_view()->GetWidget());
tray->ShowDefaultView(BUBBLE_USE_EXISTING, false /* show_by_click */);
RunAllPendingInMessageLoop();
EXPECT_EQ(bubble_bounds.ToString(), test_item->default_view()
->GetWidget()
->GetWindowBoundsInScreen()
.ToString());
EXPECT_EQ(widget, test_item->default_view()->GetWidget());
}
// Tests that the tray view is laid out properly and is fully contained within
// the shelf widget.
TEST_F(SystemTrayTest, TrayBoundsInWidget) {
Shelf* shelf = GetPrimaryShelf();
StatusAreaWidget* widget = StatusAreaWidgetTestHelper::GetStatusAreaWidget();
SystemTray* tray = GetPrimarySystemTray();
// Test in bottom alignment.
shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
gfx::Rect window_bounds = widget->GetWindowBoundsInScreen();
gfx::Rect tray_bounds = tray->GetBoundsInScreen();
EXPECT_TRUE(window_bounds.Contains(tray_bounds));
// Test in locked alignment.
shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM_LOCKED);
window_bounds = widget->GetWindowBoundsInScreen();
tray_bounds = tray->GetBoundsInScreen();
EXPECT_TRUE(window_bounds.Contains(tray_bounds));
// Test in the left alignment.
shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
window_bounds = widget->GetWindowBoundsInScreen();
tray_bounds = tray->GetBoundsInScreen();
// TODO(estade): Re-enable this check. See crbug.com/660928.
// EXPECT_TRUE(window_bounds.Contains(tray_bounds));
// Test in the right alignment.
shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
window_bounds = widget->GetWindowBoundsInScreen();
tray_bounds = tray->GetBoundsInScreen();
// TODO(estade): Re-enable this check. See crbug.com/660928.
// EXPECT_TRUE(window_bounds.Contains(tray_bounds));
}
TEST_F(SystemTrayTest, PersistentBubble) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->GetWidget());
tray->AddTrayItem(std::make_unique<TestSystemTrayItem>());
std::unique_ptr<views::Widget> widget(CreateTestWidget(
nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100)));
// Tests for usual default view while activating a window.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
tray->ActivateBubble();
ASSERT_TRUE(tray->HasSystemBubble());
widget->Activate();
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(tray->HasSystemBubble());
// Clicking outside the bubble should close it.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
ASSERT_TRUE(tray->HasSystemBubble());
{
ui::test::EventGenerator& generator = GetEventGenerator();
generator.set_current_location(gfx::Point(5, 5));
generator.ClickLeftButton();
ASSERT_FALSE(tray->HasSystemBubble());
}
// Same tests for persistent default view.
tray->ShowPersistentDefaultView();
ASSERT_TRUE(tray->HasSystemBubble());
widget->Activate();
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(tray->HasSystemBubble());
{
ui::test::EventGenerator& generator = GetEventGenerator();
generator.set_current_location(gfx::Point(5, 5));
generator.ClickLeftButton();
ASSERT_TRUE(tray->HasSystemBubble());
}
// Same tests for persistent default view with activation.
tray->ShowPersistentDefaultView();
EXPECT_TRUE(tray->HasSystemBubble());
widget->Activate();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(tray->HasSystemBubble());
ui::test::EventGenerator& generator = GetEventGenerator();
generator.set_current_location(gfx::Point(5, 5));
generator.ClickLeftButton();
EXPECT_TRUE(tray->HasSystemBubble());
}
// With a system modal dialog, the bubble should be created with a LOCKED login
// status.
TEST_F(SystemTrayTest, WithSystemModal) {
// The accessiblity item is created and is visible either way.
Shell::Get()->accessibility_delegate()->SetVirtualKeyboardEnabled(true);
std::unique_ptr<views::Widget> widget(CreateTestWidget(
new ModalWidgetDelegate, kShellWindowId_SystemModalContainer,
gfx::Rect(0, 0, 100, 100)));
SystemTray* tray = GetPrimarySystemTray();
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
ASSERT_TRUE(tray->HasSystemBubble());
const views::View* accessibility =
tray->GetSystemBubble()->bubble_view()->GetViewByID(
VIEW_ID_ACCESSIBILITY_TRAY_ITEM);
ASSERT_TRUE(accessibility);
EXPECT_TRUE(accessibility->visible());
// The bluetooth item is disabled in locked mode.
const views::View* bluetooth =
tray->GetSystemBubble()->bubble_view()->GetViewByID(
VIEW_ID_BLUETOOTH_DEFAULT_VIEW);
ASSERT_TRUE(bluetooth);
EXPECT_FALSE(bluetooth->enabled());
// Close the modal dialog.
widget.reset();
// System modal is gone. The bluetooth item should be enabled now.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
accessibility = tray->GetSystemBubble()->bubble_view()->GetViewByID(
VIEW_ID_ACCESSIBILITY_TRAY_ITEM);
ASSERT_TRUE(accessibility);
EXPECT_TRUE(accessibility->visible());
bluetooth = tray->GetSystemBubble()->bubble_view()->GetViewByID(
VIEW_ID_BLUETOOTH_DEFAULT_VIEW);
ASSERT_TRUE(bluetooth);
EXPECT_TRUE(bluetooth->enabled());
}
// Tests that if SetVisible(true) is called while animating to hidden that the
// tray becomes visible, and stops animating to hidden.
TEST_F(SystemTrayTest, SetVisibleDuringHideAnimation) {
SystemTray* tray = GetPrimarySystemTray();
ASSERT_TRUE(tray->visible());
std::unique_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration;
animation_duration.reset(new ui::ScopedAnimationDurationScaleMode(
ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
tray->SetVisible(false);
EXPECT_TRUE(tray->visible());
EXPECT_EQ(0.0f, tray->layer()->GetTargetOpacity());
tray->SetVisible(true);
animation_duration.reset();
tray->layer()->GetAnimator()->StopAnimating();
EXPECT_TRUE(tray->visible());
EXPECT_EQ(1.0f, tray->layer()->GetTargetOpacity());
}
TEST_F(SystemTrayTest, SystemTrayHeightWithBubble) {
SystemTray* tray = GetPrimarySystemTray();
WebNotificationTray* notification_tray =
StatusAreaWidgetTestHelper::GetStatusAreaWidget()
->web_notification_tray();
// Ensure the initial tray bubble height is zero.
EXPECT_EQ(0, notification_tray->tray_bubble_height_for_test());
// Show the default view, ensure the tray bubble height is changed.
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
RunAllPendingInMessageLoop();
EXPECT_LT(0, notification_tray->tray_bubble_height_for_test());
// Hide the default view, ensure the tray bubble height is back to zero.
ASSERT_TRUE(tray->HasSystemBubble());
tray->CloseBubble();
RunAllPendingInMessageLoop();
EXPECT_EQ(0, notification_tray->tray_bubble_height_for_test());
}
TEST_F(SystemTrayTest, SeparatorThickness) {
EXPECT_EQ(kSeparatorWidth, views::Separator::kThickness);
}
// System tray is not activated by default. If it is opened by user click on
// system tray, it should be activated when user presses tab key.
TEST_F(SystemTrayTest, KeyboardNavigationWithOtherWindow) {
std::unique_ptr<views::Widget> widget(CreateTestWidget(
nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100)));
EXPECT_TRUE(widget->IsActive());
// Add a view which tries to handle key event by themselves, and focus on it.
KeyEventConsumerView key_event_consumer_view;
views::View* root_view = widget->GetContentsView();
root_view->AddChildView(&key_event_consumer_view);
key_event_consumer_view.RequestFocus();
EXPECT_EQ(&key_event_consumer_view,
key_event_consumer_view.GetFocusManager()->GetFocusedView());
// Show system tray by performing a gesture tap at tray.
SystemTray* tray = GetPrimarySystemTray();
ui::GestureEvent tap(0, 0, 0, base::TimeTicks(),
ui::GestureEventDetails(ui::ET_GESTURE_TAP));
tray->PerformAction(tap);
ASSERT_TRUE(tray->GetWidget());
// Confirms that system tray is not activated at this time.
EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
EXPECT_TRUE(widget->IsActive());
ui::test::EventGenerator& event_generator = GetEventGenerator();
int number_of_consumed_key_events =
key_event_consumer_view.number_of_consumed_key_events();
// Send A key event. Nothing should happen for the tray. Key event is consumed
// by the tray.
event_generator.PressKey(ui::VKEY_A, ui::EF_NONE);
event_generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE);
EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
EXPECT_TRUE(widget->IsActive());
EXPECT_EQ(number_of_consumed_key_events,
key_event_consumer_view.number_of_consumed_key_events());
// Send tab key event.
event_generator.PressKey(ui::VKEY_TAB, ui::EF_NONE);
event_generator.ReleaseKey(ui::VKEY_TAB, ui::EF_NONE);
// Confirms that system tray is activated.
EXPECT_TRUE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
EXPECT_FALSE(widget->IsActive());
EXPECT_EQ(number_of_consumed_key_events,
key_event_consumer_view.number_of_consumed_key_events());
// Close system tray and reopen it by not explicit user click.
tray->CloseBubble();
ASSERT_FALSE(tray->IsSystemBubbleVisible());
tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
ASSERT_TRUE(tray->GetWidget());
// Confirms that system tray is not activated by tab key event to verify that
// RerouteEventHandler is not installed in this case.
event_generator.PressKey(ui::VKEY_TAB, ui::EF_NONE);
event_generator.ReleaseKey(ui::VKEY_TAB, ui::EF_NONE);
EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
EXPECT_TRUE(widget->IsActive());
}
// When System tray is opened by explicit user click, it passes a key event to
// ViewsDelegate if it's not handled by the tray. It closes the tray if
// ViewsDelegate returns CLOSE_MENU.
TEST_F(SystemTrayTest, AcceleratorController) {
// Register A key as an accelerator which closes the menu.
ui::Accelerator accelerator(ui::VKEY_A, ui::EF_NONE);
AshTestViewsDelegate* views_delegate =
ash_test_helper()->test_views_delegate();
views_delegate->set_close_menu_accelerator(accelerator);
// Show system tray by performing a gesture tap at tray.
SystemTray* tray = GetPrimarySystemTray();
ui::GestureEvent tap(0, 0, 0, base::TimeTicks(),
ui::GestureEventDetails(ui::ET_GESTURE_TAP));
tray->PerformAction(tap);
ASSERT_TRUE(tray->GetWidget());
ASSERT_TRUE(tray->IsSystemBubbleVisible());
ui::test::EventGenerator& event_generator = GetEventGenerator();
// Send B key event and confirms that nothing happens.
event_generator.PressKey(ui::VKEY_B, ui::EF_NONE);
event_generator.ReleaseKey(ui::VKEY_B, ui::EF_NONE);
EXPECT_TRUE(tray->IsSystemBubbleVisible());
// Send A key event and confirms that system tray becomes invisible.
event_generator.PressKey(ui::VKEY_A, ui::EF_NONE);
event_generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE);
EXPECT_FALSE(tray->IsSystemBubbleVisible());
}
// When system tray has an active child widget, the child widget should consume
// key event and the tray shouldn't consume key event, i.e. RerouteEventHandler
// in TrayBubbleView should not reroute key events to the tray in this case.
TEST_F(SystemTrayTest, ActiveChildWidget) {
SystemTray* tray = GetPrimarySystemTray();
tray->ShowDefaultView(BUBBLE_CREATE_NEW, true /* show_by_click */);
// Create a child widget on system tray and focus it.
views::Widget* child_widget = views::Widget::CreateWindowWithParent(
nullptr, tray->GetBubbleView()->GetWidget()->GetNativeView());
std::unique_ptr<KeyEventConsumerView> consumer_view(
new KeyEventConsumerView());
child_widget->GetContentsView()->AddChildView(consumer_view.get());
child_widget->Show();
consumer_view->RequestFocus();
ASSERT_FALSE(tray->GetBubbleView()->GetWidget()->IsActive());
ASSERT_TRUE(child_widget->IsActive());
ui::test::EventGenerator& event_generator = GetEventGenerator();
// Press ESC key and confirm that child widget consumes it. Also confirm that
// the tray does not consume the key event.
ASSERT_EQ(0, consumer_view->number_of_consumed_key_events());
ASSERT_TRUE(tray->IsSystemBubbleVisible());
event_generator.PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
event_generator.ReleaseKey(ui::VKEY_ESCAPE, ui::EF_NONE);
EXPECT_EQ(2, consumer_view->number_of_consumed_key_events());
EXPECT_TRUE(tray->IsSystemBubbleVisible());
// Hide child widget and press ESC key. Confirm that the tray consumes it and
// the tray is closed even if the tray is not active.
child_widget->Hide();
ASSERT_FALSE(tray->GetBubbleView()->GetWidget()->IsActive());
event_generator.PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
event_generator.ReleaseKey(ui::VKEY_ESCAPE, ui::EF_NONE);
EXPECT_FALSE(tray->IsSystemBubbleVisible());
}
} // namespace ash