Index: chrome/browser/metrics/tab_usage_recorder.cc |
diff --git a/chrome/browser/metrics/tab_usage_recorder.cc b/chrome/browser/metrics/tab_usage_recorder.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d5f08e3cb443b0a862c508d76b9802e2077d9b87 |
--- /dev/null |
+++ b/chrome/browser/metrics/tab_usage_recorder.cc |
@@ -0,0 +1,165 @@ |
+// 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 "chrome/browser/bookmarks/bookmark_model_factory.h" |
+#include "chrome/browser/ui/tabs/tab_strip_model.h" |
+#include "components/bookmarks/browser/bookmark_model.h" |
+#include "content/public/browser/browser_thread.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 { |
+ |
+// This global is never freed. |
+TabUsageRecorder* g_tab_usage_recorder = nullptr; |
+ |
+} // namespace |
+ |
+// This class is used to track the activation/deactivation cycle per |
+// WebContents. It also keeps track of the pinned state of the tab. |
+class TabUsageRecorder::WebContentsData |
+ : public content::WebContentsUserData<WebContentsData> { |
+ public: |
+ ~WebContentsData() override; |
+ |
+ void OnTabActivating(); |
+ void OnTabDeactivating(); |
+ void OnTabClosing(); |
+ void OnTabPinnedStateChanging(bool is_pinned); |
+ |
+ private: |
+ friend class content::WebContentsUserData<WebContentsData>; |
+ |
+ explicit WebContentsData(content::WebContents* contents); |
+ |
+ // Returns true if |contents_|'s URL is bookmarked. |
+ bool IsBookmarked(); |
+ |
+ void RecordTabDeactivation(); |
+ void RecordTabReactivation(); |
+ |
+ // The WebContents associated to this instance. |
+ content::WebContents* contents_; |
+ |
+ // Indicates if the tab is pinned to the tab strip. |
+ bool is_pinned_; |
+ |
+ // Indicates if the tab has been deactivated before as to only count |
+ // reactivations. |
+ bool was_deactivated_once_; |
+ |
+ // The deactivation metric is not recorded for closing tabs. |
+ bool is_closing_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(WebContentsData); |
+}; |
+ |
+TabUsageRecorder::WebContentsData::~WebContentsData() = default; |
+ |
+void TabUsageRecorder::WebContentsData::OnTabActivating() { |
+ if (was_deactivated_once_) |
+ RecordTabReactivation(); |
+} |
+ |
+void TabUsageRecorder::WebContentsData::OnTabDeactivating() { |
+ was_deactivated_once_ = true; |
+ if (!is_closing_) |
+ RecordTabDeactivation(); |
+} |
+ |
+void TabUsageRecorder::WebContentsData::OnTabClosing() { |
+ is_closing_ = true; |
+} |
+ |
+void TabUsageRecorder::WebContentsData::OnTabPinnedStateChanging( |
+ bool is_pinned) { |
+ is_pinned_ = is_pinned; |
+} |
+ |
+TabUsageRecorder::WebContentsData::WebContentsData( |
+ content::WebContents* contents) |
+ : contents_(contents), |
+ is_pinned_(false), |
+ was_deactivated_once_(false), |
+ is_closing_(false) {} |
+ |
+bool TabUsageRecorder::WebContentsData::IsBookmarked() { |
+ bookmarks::BookmarkModel* bookmark_model = |
+ BookmarkModelFactory::GetForBrowserContextIfExists( |
+ contents_->GetBrowserContext()); |
+ |
+ return bookmark_model && |
+ bookmark_model->IsBookmarked(contents_->GetLastCommittedURL()); |
+} |
+ |
+void TabUsageRecorder::WebContentsData::RecordTabDeactivation() { |
+ UMA_HISTOGRAM_BOOLEAN("Tab.Deactivation.Pinned", is_pinned_); |
+ UMA_HISTOGRAM_BOOLEAN( |
+ "Tab.Deactivation.HadFormInteraction", |
+ contents_->GetPageImportanceSignals().had_form_interaction); |
+ UMA_HISTOGRAM_BOOLEAN("Tab.Deactivation.Bookmarked", IsBookmarked()); |
+} |
+ |
+void TabUsageRecorder::WebContentsData::RecordTabReactivation() { |
+ UMA_HISTOGRAM_BOOLEAN("Tab.Reactivation.Pinned", is_pinned_); |
+ UMA_HISTOGRAM_BOOLEAN( |
+ "Tab.Reactivation.HadFormInteraction", |
+ contents_->GetPageImportanceSignals().had_form_interaction); |
+ UMA_HISTOGRAM_BOOLEAN("Tab.Reactivation.Bookmarked", IsBookmarked()); |
+} |
+ |
+// static |
+void TabUsageRecorder::Initialize() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ DCHECK(!g_tab_usage_recorder); |
+ g_tab_usage_recorder = new TabUsageRecorder(); |
+} |
+ |
+void TabUsageRecorder::TabInsertedAt(TabStripModel* tab_strip_model, |
+ content::WebContents* contents, |
+ int index, |
+ bool foreground) { |
+ WebContentsData::CreateForWebContents(contents); |
Georges Khalil
2016/09/20 21:36:31
I think we can have news WebContentses that don't
Patrick Monette
2016/09/21 21:03:18
Done.
|
+ // Set the initial pinned value. |
+ TabPinnedStateChanged(tab_strip_model, contents, index); |
+} |
+ |
+void TabUsageRecorder::TabClosingAt(TabStripModel* tab_strip_model, |
+ content::WebContents* contents, |
+ int index) { |
+ WebContentsData::FromWebContents(contents)->OnTabClosing(); |
+} |
+ |
+void TabUsageRecorder::ActiveTabChanged(content::WebContents* old_contents, |
+ content::WebContents* new_contents, |
+ int index, |
+ int reason) { |
+ if (old_contents) |
+ WebContentsData::FromWebContents(old_contents)->OnTabDeactivating(); |
+ WebContentsData::FromWebContents(new_contents)->OnTabActivating(); |
+} |
+ |
+void TabUsageRecorder::TabPinnedStateChanged(TabStripModel* tab_strip_model, |
+ content::WebContents* contents, |
+ int index) { |
+ WebContentsData::FromWebContents(contents)->OnTabPinnedStateChanging( |
+ tab_strip_model->IsTabPinned(index)); |
+} |
+ |
+TabUsageRecorder::TabUsageRecorder() |
+ : browser_tab_strip_tracker_(this, nullptr, nullptr) { |
+ browser_tab_strip_tracker_.Init( |
+ BrowserTabStripTracker::InitWith::ALL_BROWERS); |
+} |
+ |
+TabUsageRecorder::~TabUsageRecorder() = default; |
+ |
+} // namespace metrics |