Skip to content

Commit

Permalink
snap-groups: Record close two windows duration
Browse files Browse the repository at this point in the history
These metrics will be used by Snap Groups to record the distribution
of a snapped window getting closed then another snapped window
getting closed or unsnapped within X minutes, where X is very low.

Since the window gets reset, we will just record the state type at the
time it is destroyed and find any other snapped window of the opposite
state type that also gets destroyed. If any other snapped window of
the opposite state type is unsnapped, it will record the max duration.

Test: added
Fixed: b/302733248
Change-Id: I9a56f72ba158da26c71a4d3ebeb13748fcdf83a8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4906312
Reviewed-by: Michele Fan <michelefan@chromium.org>
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Commit-Queue: Sophie Wen <sophiewen@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1209221}
  • Loading branch information
sophiewen authored and Chromium LUCI CQ committed Oct 13, 2023
1 parent ad920e1 commit b468a92
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 69 deletions.
44 changes: 44 additions & 0 deletions ash/wm/splitview/split_view_metrics_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,15 @@ void SplitViewMetricsController::OnPostWindowStateTypeChange(
if (is_snapped == was_snapped)
return;

if (was_snapped &&
chromeos::IsSnappedWindowStateType(first_closed_state_type_) &&
old_type != first_closed_state_type_) {
// If a window in the opposite side of `first_closed_state_type_` gets
// unsnapped, record the max duration to indicate a second snapped window
// was never closed after the first window.
RecordCloseTwoWindowsDuration(kSequentialSnapActionMaxTime);
}

MaybeStartOrEndRecordBothSnappedClamshellSplitView();
}

Expand Down Expand Up @@ -529,6 +538,10 @@ void SplitViewMetricsController::AddObservedWindow(aura::Window* window) {
}

void SplitViewMetricsController::RemoveObservedWindow(aura::Window* window) {
if (window->is_destroying()) {
MaybeStartOrEndRecordCloseTwoWindowsDuration(window);
}

if (window == first_snapped_window_) {
if (window->is_destroying()) {
// If `first_snapped_window_` was destroyed, record the max duration to
Expand Down Expand Up @@ -662,6 +675,17 @@ void SplitViewMetricsController::RecordMinimizeTwoWindowsDuration(
first_minimized_time_ = base::TimeTicks();
}

void SplitViewMetricsController::RecordCloseTwoWindowsDuration(
const base::TimeDelta& elapsed_time) {
base::UmaHistogramCustomTimes(kCloseTwoWindowsDurationHistogramName,
/*sample=*/elapsed_time,
kSequentialSnapActionMinTime,
kSequentialSnapActionMaxTime, /*buckets=*/100);
// Reset `first_closed_state_type_` to kDefault to stop recording.
first_closed_state_type_ = chromeos::WindowStateType::kDefault;
first_closed_time_ = base::TimeTicks();
}

void SplitViewMetricsController::MaybeStartOrEndRecordSnapTwoWindowsDuration(
WindowState* window_state) {
if (window_state->IsSnapped()) {
Expand Down Expand Up @@ -714,6 +738,26 @@ void SplitViewMetricsController::
}
}

void SplitViewMetricsController::MaybeStartOrEndRecordCloseTwoWindowsDuration(
aura::Window* window) {
if (auto* window_state = WindowState::Get(window);
window_state && window_state->IsSnapped()) {
if (!chromeos::IsSnappedWindowStateType(first_closed_state_type_)) {
// If `first_closed_state_type_` is reset to kDefault, start recording.
first_closed_state_type_ = window_state->GetStateType();
first_closed_time_ = base::TimeTicks::Now();
return;
}
// If `window` has the opposite state type of `first_closed_state_type_`,
// record the duration.
if (GetOppositeSnapType(window) == first_closed_state_type_ &&
!first_closed_time_.is_null()) {
RecordCloseTwoWindowsDuration(base::TimeTicks::Now() -
first_closed_time_);
}
}
}

void SplitViewMetricsController::ResetTimeAndCounter() {
clamshell_split_view_start_time_ = kInvalidTime;
tablet_split_view_start_time_ = kInvalidTime;
Expand Down
40 changes: 30 additions & 10 deletions ash/wm/splitview/split_view_metrics_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chromeos/ui/base/window_state_type.h"
#include "ui/aura/env_observer.h"
#include "ui/aura/window_observer.h"
#include "ui/display/display_observer.h"
Expand All @@ -30,9 +31,11 @@ class SplitViewController;

// Public so it can be used by unit tests.
constexpr char kSnapTwoWindowsDurationHistogramName[] =
"Ash.Window.SnapTwoWindowsDuration";
"Ash.Snap.SnapTwoWindowsDuration";
constexpr char kMinimizeTwoWindowsDurationHistogramName[] =
"Ash.Window.MinimizeTwoWindowsDuration";
"Ash.Snap.MinimizeTwoWindowsDuration";
constexpr char kCloseTwoWindowsDurationHistogramName[] =
"Ash.Snap.CloseTwoWindowsDuration";
constexpr base::TimeDelta kSequentialSnapActionMinTime = base::Seconds(1);
constexpr base::TimeDelta kSequentialSnapActionMaxTime = base::Hours(50);

Expand Down Expand Up @@ -179,6 +182,17 @@ class SplitViewMetricsController : public TabletModeObserver,
// minimized.
void RecordMinimizeTwoWindowsDuration(const base::TimeDelta& elapsed_time);

// Records and resets the duration between two snapped windows getting
// closed.
void RecordCloseTwoWindowsDuration(const base::TimeDelta& elapsed_time);

// Starts recording the time if `window_state` was the first snapped window.
// Ends recording if either:
// 1. A second window is snapped;
// 2. The first window is unsnapped;
// 3. The first window is destroyed.
void MaybeStartOrEndRecordSnapTwoWindowsDuration(WindowState* window_state);

// Starts recording the time if `window_state` changed from snapped to
// minimized. Ends recording if either:
// 1. A second window state changes from snapped to minimized;
Expand All @@ -188,12 +202,11 @@ class SplitViewMetricsController : public TabletModeObserver,
WindowState* window_state,
chromeos::WindowStateType old_type);

// Starts recording the time if `window_state` was the first snapped window.
// Ends recording if either:
// 1. A second window is snapped;
// 2. The first window is unsnapped;
// 3. The first window is destroyed.
void MaybeStartOrEndRecordSnapTwoWindowsDuration(WindowState* window_state);
// Starts recording the time if `window` was snapped and gets closed, i.e.
// destroyed. Ends recording if either:
// 1. A second snapped window is closed;
// 2. A second snapped window is unsnapped.
void MaybeStartOrEndRecordCloseTwoWindowsDuration(aura::Window* window);

// Resets the variables related to time and counter metrics.
void ResetTimeAndCounter();
Expand Down Expand Up @@ -276,16 +289,23 @@ class SplitViewMetricsController : public TabletModeObserver,
int swap_count_ = 0;

// The first window that gets snapped and the time it's snapped at. Used by
// `Ash.Window.SnapTwoWindowsDuration` in
// `Ash.Snap.SnapTwoWindowsDuration` in
// tools/metrics/histograms/metadata/ash/histograms.xml.
raw_ptr<aura::Window> first_snapped_window_ = nullptr;
base::TimeTicks first_snapped_time_;

// The first snapped window that gets minimized and the time it's minimized.
// Used by `Ash.Window.MinimizeTwoWindowsDuration` in
// Used by `Ash.Snap.MinimizeTwoWindowsDuration` in
// tools/metrics/histograms/metadata/ash/histograms.xml.
raw_ptr<WindowState> first_minimized_window_state_ = nullptr;
base::TimeTicks first_minimized_time_;

// The first snapped window that gets closed and the time it's closed.
// Used by `Ash.Snap.CloseTwoWindowsDuration` in
// tools/metrics/histograms/metadata/ash/histograms.xml.
chromeos::WindowStateType first_closed_state_type_ =
chromeos::WindowStateType::kDefault;
base::TimeTicks first_closed_time_;
};

} // namespace ash
Expand Down

0 comments on commit b468a92

Please sign in to comment.