blob: 15b0e16e22d6a77ad3c7e738548ddb3330bca466 [file] [log] [blame]
// Copyright 2016 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 "chrome/browser/metrics/tab_usage_recorder.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/page_importance_signals.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(metrics::TabUsageRecorder::WebContentsData);
namespace metrics {
namespace {
// The recorder is never stopped, thus it is ok to leak.
TabUsageRecorder* g_tab_usage_recorder = nullptr;
} // namespace
// This class is responsible for recording the metrics. It also keeps track of
// the pinned state of the tab.
class TabUsageRecorder::WebContentsData
: public content::WebContentsUserData<WebContentsData> {
public:
~WebContentsData() override;
void RecordTabDeactivation();
void RecordTabReactivation();
void OnTabPinnedStateChanging(bool is_pinned);
private:
friend class content::WebContentsUserData<WebContentsData>;
explicit WebContentsData(content::WebContents* contents);
// The WebContents associated to this instance.
content::WebContents* contents_;
// Indicates if the tab is pinned to the tab strip.
bool is_pinned_;
base::TimeTicks last_inactive_time_;
DISALLOW_COPY_AND_ASSIGN(WebContentsData);
};
TabUsageRecorder::WebContentsData::~WebContentsData() = default;
void TabUsageRecorder::WebContentsData::OnTabPinnedStateChanging(
bool is_pinned) {
is_pinned_ = is_pinned;
}
TabUsageRecorder::WebContentsData::WebContentsData(
content::WebContents* contents)
: contents_(contents), is_pinned_(false) {}
void TabUsageRecorder::WebContentsData::RecordTabDeactivation() {
last_inactive_time_ = base::TimeTicks::Now();
UMA_HISTOGRAM_BOOLEAN("Tab.Deactivation.Pinned", is_pinned_);
UMA_HISTOGRAM_BOOLEAN(
"Tab.Deactivation.HadFormInteraction",
contents_->GetPageImportanceSignals().had_form_interaction);
}
void TabUsageRecorder::WebContentsData::RecordTabReactivation() {
bool had_form_interaction =
contents_->GetPageImportanceSignals().had_form_interaction;
UMA_HISTOGRAM_BOOLEAN("Tab.Reactivation.Pinned", is_pinned_);
UMA_HISTOGRAM_BOOLEAN("Tab.Reactivation.HadFormInteraction",
had_form_interaction);
base::TimeDelta time_to_reactivation =
base::TimeTicks::Now() - last_inactive_time_;
if (is_pinned_ || had_form_interaction) {
UMA_HISTOGRAM_CUSTOM_TIMES(
"Tab.TimeToReactivation.Important", time_to_reactivation,
base::TimeDelta::FromSeconds(1), base::TimeDelta::FromHours(2), 100);
} else {
UMA_HISTOGRAM_CUSTOM_TIMES(
"Tab.TimeToReactivation.Normal", time_to_reactivation,
base::TimeDelta::FromSeconds(1), base::TimeDelta::FromHours(2), 100);
}
}
// static
void TabUsageRecorder::InitializeIfNeeded() {
if (!g_tab_usage_recorder)
g_tab_usage_recorder = new TabUsageRecorder();
}
void TabUsageRecorder::OnTabDeactivated(content::WebContents* contents) {
GetWebContentsData(contents)->RecordTabDeactivation();
}
void TabUsageRecorder::OnTabReactivated(content::WebContents* contents) {
GetWebContentsData(contents)->RecordTabReactivation();
}
void TabUsageRecorder::TabInsertedAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index,
bool foreground) {
// Set the initial pin state.
TabPinnedStateChanged(tab_strip_model, contents, index);
}
void TabUsageRecorder::TabPinnedStateChanged(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index) {
GetWebContentsData(contents)->OnTabPinnedStateChanging(
tab_strip_model->IsTabPinned(index));
}
TabUsageRecorder::TabUsageRecorder()
: tab_reactivation_tracker_(this),
browser_tab_strip_tracker_(this, nullptr, nullptr) {
browser_tab_strip_tracker_.Init();
}
TabUsageRecorder::~TabUsageRecorder() = default;
TabUsageRecorder::WebContentsData* TabUsageRecorder::GetWebContentsData(
content::WebContents* contents) {
WebContentsData::CreateForWebContents(contents);
return WebContentsData::FromWebContents(contents);
}
} // namespace metrics