blob: 2e70537867b79620cef67e1ca1d08787cab10765 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/unified/date_tray.h"
#include "ash/public/cpp/test/shell_test_api.h"
#include "ash/shell.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/status_area_widget_test_helper.h"
#include "ash/system/time/time_tray_item_view.h"
#include "ash/system/time/time_view.h"
#include "ash/system/unified/glanceable_tray_bubble.h"
#include "ash/system/unified/unified_system_tray_bubble.h"
#include "ash/test/ash_test_base.h"
#include "base/memory/raw_ptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/time/time_override.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/wm/public/activation_change_observer.h"
#include "ui/wm/public/activation_client.h"
namespace ash {
class DateTrayTest
: public AshTestBase,
public wm::ActivationChangeObserver,
public testing::WithParamInterface</*glanceables_v2_enabled=*/bool> {
public:
DateTrayTest() {
scoped_feature_list_.InitWithFeatureState(features::kGlanceablesV2,
GetParam());
}
DateTrayTest(const DateTrayTest&) = delete;
DateTrayTest& operator=(const DateTrayTest&) = delete;
~DateTrayTest() override = default;
void SetUp() override {
// Set time override.
base::subtle::ScopedTimeClockOverrides time_override(
[]() {
base::Time date;
bool result = base::Time::FromString("24 Aug 2021 10:00 GMT", &date);
DCHECK(result);
return date;
},
/*time_ticks_override=*/nullptr,
/*thread_ticks_override=*/nullptr);
AshTestBase::SetUp();
widget_ = CreateFramelessTestWidget();
widget_->SetContentsView(std::make_unique<views::View>());
widget_->SetFullscreen(true);
date_tray_ = StatusAreaWidgetTestHelper::GetStatusAreaWidget()->date_tray();
unified_system_tray_ = StatusAreaWidgetTestHelper::GetStatusAreaWidget()
->unified_system_tray();
widget_->GetContentsView()->AddChildView(date_tray_.get());
widget_->GetContentsView()->AddChildView(unified_system_tray_);
date_tray_->SetVisiblePreferred(true);
date_tray_->unified_system_tray_->SetVisiblePreferred(true);
}
void TearDown() override {
widget_.reset();
date_tray_ = nullptr;
if (observering_activation_changes_) {
Shell::Get()->activation_client()->RemoveObserver(this);
}
AshTestBase::TearDown();
}
bool AreGlanceablesV2Enabled() { return GetParam(); }
DateTray* GetDateTray() { return date_tray_; }
UnifiedSystemTray* GetUnifiedSystemTray() {
return date_tray_->unified_system_tray_;
}
GlanceableTrayBubble* GetGlanceableTrayBubble() {
return date_tray_->bubble_.get();
}
bool IsBubbleShown() {
if (AreGlanceablesV2Enabled()) {
return !!GetGlanceableTrayBubble();
}
return GetUnifiedSystemTray()->IsBubbleShown();
}
bool AreContentsViewShown() {
if (AreGlanceablesV2Enabled()) {
return !!GetGlanceableTrayBubble();
}
return GetUnifiedSystemTray()->IsShowingCalendarView();
}
void LeftClickOnOpenBubble() {
if (AreGlanceablesV2Enabled()) {
LeftClickOn(GetGlanceableTrayBubble()->GetBubbleView());
} else {
LeftClickOn(GetUnifiedSystemTray()->bubble()->GetBubbleView());
}
}
std::u16string GetTimeViewText() {
return date_tray_->time_view_->time_view()
->horizontal_label_date_for_test()
->GetText();
}
void ImmediatelyCloseBubbleOnActivation() {
Shell::Get()->activation_client()->AddObserver(this);
observering_activation_changes_ = true;
}
// wm::ActivationChangeObserver:
void OnWindowActivated(ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override {
GetUnifiedSystemTray()->CloseBubble();
}
private:
std::unique_ptr<views::Widget> widget_;
bool observering_activation_changes_ = false;
// Owned by `widget_`.
raw_ptr<DateTray, ExperimentalAsh> date_tray_ = nullptr;
UnifiedSystemTray* unified_system_tray_ = nullptr;
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(GlanceablesV2, DateTrayTest, testing::Bool());
// Tests that toggling the `CalendarView` via the date tray accelerator does not
// result in a crash when the unified system tray bubble is set to immediately
// close upon activation. See crrev/c/1419499 for details.
TEST_P(DateTrayTest, AcceleratorOpenAndImmediateCloseDoesNotCrash) {
ImmediatelyCloseBubbleOnActivation();
ShellTestApi().PressAccelerator(
ui::Accelerator(ui::VKEY_C, ui::EF_COMMAND_DOWN));
EXPECT_FALSE(IsBubbleShown());
}
// Test the initial state.
TEST_P(DateTrayTest, InitialState) {
// Show the mock time now Month and day.
EXPECT_EQ(u"Aug 24", GetTimeViewText());
// Initial state: not showing the calendar bubble.
EXPECT_FALSE(IsBubbleShown());
EXPECT_FALSE(AreContentsViewShown());
}
// Tests clicking/tapping the DateTray shows/closes the calendar bubble.
TEST_P(DateTrayTest, ShowCalendarBubble) {
base::HistogramTester histogram_tester;
// Clicking on the `DateTray` -> show the calendar bubble.
LeftClickOn(GetDateTray());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsBubbleShown());
EXPECT_TRUE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_TRUE(GetDateTray()->is_active());
histogram_tester.ExpectTotalCount("Ash.Calendar.ShowSource.TimeView",
AreGlanceablesV2Enabled() ? 0 : 1);
// Clicking on the `DateTray` again -> close the calendar bubble.
LeftClickOn(GetDateTray());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_FALSE(GetDateTray()->is_active());
// Tapping on the `DateTray` again -> open the calendar bubble.
GestureTapOn(GetDateTray());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsBubbleShown());
EXPECT_TRUE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_TRUE(GetDateTray()->is_active());
histogram_tester.ExpectTotalCount("Ash.Calendar.ShowSource.TimeView",
AreGlanceablesV2Enabled() ? 0 : 2);
// Tapping on the `DateTray` again -> close the calendar bubble.
GestureTapOn(GetDateTray());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(IsBubbleShown());
EXPECT_FALSE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_FALSE(GetDateTray()->is_active());
}
// Tests the behavior when clicking on different areas.
TEST_P(DateTrayTest, ClickingArea) {
// Clicking on the `DateTray` -> show the calendar bubble.
LeftClickOn(GetDateTray());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_TRUE(GetDateTray()->is_active());
// Clicking on the bubble area -> not close the calendar bubble.
LeftClickOnOpenBubble();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_TRUE(GetDateTray()->is_active());
// Clicking on the `UnifiedSystemTray` -> switch to QS bubble.
LeftClickOn(GetUnifiedSystemTray());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(GetUnifiedSystemTray()->IsBubbleShown());
EXPECT_TRUE(GetUnifiedSystemTray()->is_active());
EXPECT_FALSE(GetDateTray()->is_active());
// Clicking on the `DateTray` -> switch to the calendar bubble.
LeftClickOn(GetDateTray());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_TRUE(GetDateTray()->is_active());
// Clicking on `DateTray` closes the bubble.
LeftClickOn(GetDateTray());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(IsBubbleShown());
EXPECT_FALSE(GetUnifiedSystemTray()->IsBubbleShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_FALSE(GetDateTray()->is_active());
}
TEST_P(DateTrayTest, EscapeKeyForClose) {
base::HistogramTester histogram_tester;
// Clicking on the `DateTray` -> show the calendar bubble.
LeftClickOn(GetDateTray());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsBubbleShown());
EXPECT_TRUE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_TRUE(GetDateTray()->is_active());
histogram_tester.ExpectTotalCount("Ash.Calendar.ShowSource.TimeView",
AreGlanceablesV2Enabled() ? 0 : 1);
// Hitting escape key -> close and deactivate the calendar bubble.
PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_FALSE(GetDateTray()->is_active());
}
// Tests that calling `DateTray::CloseBubble()` actually closes the bubble.
TEST_P(DateTrayTest, CloseBubble) {
ASSERT_FALSE(IsBubbleShown());
// Clicking on the `DateTray` -> show the calendar bubble.
LeftClickOn(GetDateTray());
EXPECT_TRUE(IsBubbleShown());
EXPECT_TRUE(AreContentsViewShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_TRUE(GetDateTray()->is_active());
// Calling `DateTray::CloseBubble()` should close the bubble.
GetDateTray()->CloseBubble();
EXPECT_FALSE(IsBubbleShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_FALSE(GetDateTray()->is_active());
// Calling `DateTray::CloseBubble()` on an already-closed bubble should do
// nothing.
GetDateTray()->CloseBubble();
EXPECT_FALSE(IsBubbleShown());
EXPECT_FALSE(GetUnifiedSystemTray()->is_active());
EXPECT_FALSE(GetDateTray()->is_active());
}
} // namespace ash