#include "ash/wm/splitview/split_view_metrics_controller.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desks_controller.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_utils.h"
#include "ash/wm/wm_event.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
namespace ash {
class SplitViewMetricsControllerTest : public AshTestBase {
public:
SplitViewMetricsControllerTest()
: AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
void SetUp() override {
AshTestBase::SetUp();
window1_ = CreateAppWindow();
window2_ = CreateAppWindow();
window3_ = CreateAppWindow();
window4_ = CreateAppWindow();
}
void TearDown() override {
window1_.reset();
window2_.reset();
window3_.reset();
window4_.reset();
AshTestBase::TearDown();
}
void AdvanceClock(base::TimeDelta delta) {
task_environment()->AdvanceClock(delta);
task_environment()->RunUntilIdle();
}
protected:
std::unique_ptr<aura::Window> window1_;
std::unique_ptr<aura::Window> window2_;
std::unique_ptr<aura::Window> window3_;
std::unique_ptr<aura::Window> window4_;
base::HistogramTester histogram_tester_;
};
TEST_F(SplitViewMetricsControllerTest, RecordSnapTwoWindowsDuration) {
auto* desks_controller = DesksController::Get();
desks_controller->NewDesk(DesksCreationRemovalSource::kKeyboard);
const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
WindowState* window_state1 = WindowState::Get(window1_.get());
window_state1->OnWMEvent(&snap_left);
const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
window_state1->OnWMEvent(&snap_right);
AdvanceClock(base::Minutes(1));
histogram_tester_.ExpectTotalCount(kSnapTwoWindowsDurationHistogramName, 0);
window_state1->OnWMEvent(&snap_left);
AdvanceClock(base::Seconds(30));
WindowState* window_state2 = WindowState::Get(window2_.get());
window_state2->OnWMEvent(&snap_right);
histogram_tester_.ExpectTimeBucketCount(kSnapTwoWindowsDurationHistogramName,
base::Seconds(30), 1);
window_state2->OnWMEvent(&snap_left);
AdvanceClock(base::Minutes(3));
window_state1->OnWMEvent(&snap_right);
histogram_tester_.ExpectTimeBucketCount(kSnapTwoWindowsDurationHistogramName,
base::Minutes(3), 1);
window_state1->OnWMEvent(&snap_left);
AdvanceClock(base::Minutes(3));
window3_.reset();
window_state2->OnWMEvent(&snap_right);
histogram_tester_.ExpectTimeBucketCount(kSnapTwoWindowsDurationHistogramName,
base::Minutes(3), 2);
window_state1->OnWMEvent(&snap_right);
AdvanceClock(base::Minutes(3));
window_state1->Minimize();
histogram_tester_.ExpectTimeBucketCount(kSnapTwoWindowsDurationHistogramName,
kSequentialSnapActionMaxTime, 1);
WindowState::Get(window4_.get())->OnWMEvent(&snap_left);
AdvanceClock(base::Minutes(3));
window4_.reset();
histogram_tester_.ExpectTimeBucketCount(kSnapTwoWindowsDurationHistogramName,
kSequentialSnapActionMaxTime, 2);
window_state1->OnWMEvent(&snap_left);
AdvanceClock(base::Minutes(3));
desks_controller->NewDesk(DesksCreationRemovalSource::kKeyboard);
desks_controller->desks()[0]->MoveWindowToDesk(
window1_.get(), desks_controller->desks()[1].get(),
window1_->GetRootWindow(), true);
desks_controller->desks()[0]->MoveWindowToDesk(
window2_.get(), desks_controller->desks()[1].get(),
window2_->GetRootWindow(), true);
histogram_tester_.ExpectTotalCount(kSnapTwoWindowsDurationHistogramName, 5);
}
TEST_F(SplitViewMetricsControllerTest, RecordMinimizeTwoWindowsDuration) {
const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
WindowState* window_state1 = WindowState::Get(window1_.get());
window_state1->OnWMEvent(&snap_left);
const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
WindowState* window_state2 = WindowState::Get(window2_.get());
window_state2->OnWMEvent(&snap_right);
histogram_tester_.ExpectTotalCount(kSnapTwoWindowsDurationHistogramName, 1);
window_state1->Minimize();
AdvanceClock(base::Minutes(3));
window_state2->Minimize();
histogram_tester_.ExpectTimeBucketCount(
kMinimizeTwoWindowsDurationHistogramName, base::Minutes(3), 1);
window_state1->Restore();
window_state2->Restore();
EXPECT_TRUE(window_state1->IsSnapped());
EXPECT_TRUE(window_state2->IsSnapped());
window_state1->Minimize();
AdvanceClock(base::Minutes(3));
window_state1->Maximize();
histogram_tester_.ExpectTimeBucketCount(
kMinimizeTwoWindowsDurationHistogramName, kSequentialSnapActionMaxTime,
1);
window_state1->OnWMEvent(&snap_left);
window_state1->Minimize();
AdvanceClock(base::Minutes(3));
window_state1->Restore();
EXPECT_TRUE(window_state1->IsSnapped());
window_state1->Minimize();
histogram_tester_.ExpectTotalCount(kMinimizeTwoWindowsDurationHistogramName,
3);
window_state1->OnWMEvent(&snap_left);
window_state2->OnWMEvent(&snap_right);
EXPECT_TRUE(window_state1->IsSnapped());
EXPECT_TRUE(window_state2->IsSnapped());
window_state2->Minimize();
AdvanceClock(base::Minutes(3));
window2_.reset();
histogram_tester_.ExpectTimeBucketCount(
kMinimizeTwoWindowsDurationHistogramName, kSequentialSnapActionMaxTime,
2);
histogram_tester_.ExpectTotalCount(kMinimizeTwoWindowsDurationHistogramName,
4);
}
TEST_F(SplitViewMetricsControllerTest, CloseSnapTwoWindowsDuration) {
const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
WindowState* window_state1 = WindowState::Get(window1_.get());
window_state1->OnWMEvent(&snap_left);
WindowState* window_state2 = WindowState::Get(window2_.get());
const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
window_state2->OnWMEvent(&snap_right);
window1_.reset();
AdvanceClock(base::Minutes(3));
window2_.reset();
histogram_tester_.ExpectTimeBucketCount(kCloseTwoWindowsDurationHistogramName,
base::Minutes(3), 1);
WindowState* window_state3 = WindowState::Get(window3_.get());
WindowState* window_state4 = WindowState::Get(window4_.get());
window_state3->OnWMEvent(&snap_left);
window_state4->OnWMEvent(&snap_right);
window3_.reset();
AdvanceClock(base::Minutes(5));
window_state4->Maximize();
histogram_tester_.ExpectTimeBucketCount(kCloseTwoWindowsDurationHistogramName,
kSequentialSnapActionMaxTime, 1);
}
TEST_F(SplitViewMetricsControllerTest, FloatToSnap) {
WindowState* window_state1 = WindowState::Get(window1_.get());
const WindowFloatWMEvent float_event(
chromeos::FloatStartLocation::kBottomRight);
window_state1->OnWMEvent(&float_event);
WindowState* window_state2 = WindowState::Get(window2_.get());
const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY,
chromeos::kOneThirdSnapRatio);
window_state2->OnWMEvent(&snap_right);
window_state2->OnWMEvent(&float_event);
window_state1->OnWMEvent(&snap_right);
window_state1->OnWMEvent(&float_event);
}
TEST_F(SplitViewMetricsControllerTest, SnapWindowSuggestions) {
PrefService* pref =
Shell::Get()->session_controller()->GetActivePrefService();
ASSERT_TRUE(pref->GetBoolean(prefs::kSnapWindowSuggestions));
const auto snap_action_sources = {
WindowSnapActionSource::kSnapByWindowLayoutMenu,
WindowSnapActionSource::kDragWindowToEdgeToSnap,
WindowSnapActionSource::kLongPressCaptionButtonToSnap,
WindowSnapActionSource::kKeyboardShortcutToSnap,
WindowSnapActionSource::kSnapByWindowStateRestore,
WindowSnapActionSource::kSnapByFullRestoreOrDeskTemplateOrSavedDesk,
};
for (const auto snap_action_source : snap_action_sources) {
std::string histogram_name(
BuildSnapWindowSuggestionsHistogramName(snap_action_source));
histogram_tester_.ExpectTotalCount(histogram_name,
0);
bool increment =
CanSnapActionSourceStartFasterSplitView(snap_action_source);
pref->SetBoolean(prefs::kSnapWindowSuggestions, true);
const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY,
snap_action_source);
WindowState* window_state1 = WindowState::Get(window1_.get());
window_state1->OnWMEvent(&snap_left);
histogram_tester_.ExpectBucketCount(histogram_name,
true,
increment ? 1 : 0);
pref->SetBoolean(prefs::kSnapWindowSuggestions, false);
const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY,
snap_action_source);
window_state1->OnWMEvent(&snap_right);
histogram_tester_.ExpectBucketCount(histogram_name,
false,
increment ? 1 : 0);
}
}
}