popup_opener_tab_helper.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/blocked_content/popup_opener_tab_helper.h"
  5. #include <utility>
  6. #include "base/check.h"
  7. #include "base/memory/ptr_util.h"
  8. #include "base/metrics/histogram_macros.h"
  9. #include "base/time/tick_clock.h"
  10. #include "components/blocked_content/popup_tracker.h"
  11. #include "components/content_settings/core/browser/host_content_settings_map.h"
  12. #include "components/content_settings/core/common/content_settings.h"
  13. #include "content/public/browser/navigation_handle.h"
  14. #include "content/public/browser/web_contents.h"
  15. #include "services/metrics/public/cpp/metrics_utils.h"
  16. #include "services/metrics/public/cpp/ukm_builders.h"
  17. #include "services/metrics/public/cpp/ukm_recorder.h"
  18. #include "ui/base/scoped_visibility_tracker.h"
  19. namespace blocked_content {
  20. PopupOpenerTabHelper::~PopupOpenerTabHelper() {
  21. DCHECK(visibility_tracker_);
  22. base::TimeDelta total_visible_time =
  23. visibility_tracker_->GetForegroundDuration();
  24. if (did_tab_under()) {
  25. UMA_HISTOGRAM_LONG_TIMES(
  26. "Tab.TabUnder.VisibleTime",
  27. total_visible_time - visible_time_before_tab_under_.value());
  28. UMA_HISTOGRAM_LONG_TIMES("Tab.TabUnder.VisibleTimeBefore",
  29. visible_time_before_tab_under_.value());
  30. }
  31. UMA_HISTOGRAM_LONG_TIMES("Tab.VisibleTime", total_visible_time);
  32. }
  33. void PopupOpenerTabHelper::OnOpenedPopup(PopupTracker* popup_tracker) {
  34. has_opened_popup_since_last_user_gesture_ = true;
  35. MaybeLogPagePopupContentSettings();
  36. last_popup_open_time_ = tick_clock_->NowTicks();
  37. }
  38. void PopupOpenerTabHelper::OnDidTabUnder() {
  39. // The tab already did a tab-under.
  40. if (did_tab_under())
  41. return;
  42. // Tab-under requires a popup, so this better not be null.
  43. DCHECK(!last_popup_open_time_.is_null());
  44. UMA_HISTOGRAM_LONG_TIMES("Tab.TabUnder.PopupToTabUnderTime",
  45. tick_clock_->NowTicks() - last_popup_open_time_);
  46. visible_time_before_tab_under_ = visibility_tracker_->GetForegroundDuration();
  47. }
  48. PopupOpenerTabHelper::PopupOpenerTabHelper(content::WebContents* web_contents,
  49. const base::TickClock* tick_clock,
  50. HostContentSettingsMap* settings_map)
  51. : content::WebContentsObserver(web_contents),
  52. content::WebContentsUserData<PopupOpenerTabHelper>(*web_contents),
  53. tick_clock_(tick_clock),
  54. settings_map_(settings_map) {
  55. visibility_tracker_ = std::make_unique<ui::ScopedVisibilityTracker>(
  56. tick_clock_,
  57. web_contents->GetVisibility() != content::Visibility::HIDDEN);
  58. }
  59. void PopupOpenerTabHelper::OnVisibilityChanged(content::Visibility visibility) {
  60. // TODO(csharrison): Consider handling OCCLUDED tabs the same way as HIDDEN
  61. // tabs.
  62. if (visibility == content::Visibility::HIDDEN)
  63. visibility_tracker_->OnHidden();
  64. else
  65. visibility_tracker_->OnShown();
  66. }
  67. void PopupOpenerTabHelper::DidGetUserInteraction(
  68. const blink::WebInputEvent& event) {
  69. has_opened_popup_since_last_user_gesture_ = false;
  70. }
  71. void PopupOpenerTabHelper::DidStartNavigation(
  72. content::NavigationHandle* navigation_handle) {
  73. // Treat browser-initiated navigations as user interactions.
  74. // Note that |HasUserGesture| does not capture browser-initiated navigations.
  75. // The negation of |IsRendererInitiated| tells us whether the navigation is
  76. // browser-generated.
  77. if (navigation_handle->IsInPrimaryMainFrame() &&
  78. (navigation_handle->HasUserGesture() ||
  79. !navigation_handle->IsRendererInitiated())) {
  80. has_opened_popup_since_last_user_gesture_ = false;
  81. }
  82. }
  83. void PopupOpenerTabHelper::MaybeLogPagePopupContentSettings() {
  84. // If the user has opened a popup, record the page popup settings ukm.
  85. const GURL& url = web_contents()->GetLastCommittedURL();
  86. if (!url.is_valid())
  87. return;
  88. const ukm::SourceId source_id =
  89. web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId();
  90. // Do not record duplicate Popup.Page events for popups opened in succession
  91. // from the same opener.
  92. if (source_id != last_opener_source_id_) {
  93. bool user_allows_popups =
  94. settings_map_->GetContentSetting(
  95. url, url, ContentSettingsType::POPUPS) == CONTENT_SETTING_ALLOW;
  96. ukm::builders::Popup_Page(source_id)
  97. .SetAllowed(user_allows_popups)
  98. .Record(ukm::UkmRecorder::Get());
  99. last_opener_source_id_ = source_id;
  100. }
  101. }
  102. WEB_CONTENTS_USER_DATA_KEY_IMPL(PopupOpenerTabHelper);
  103. } // namespace blocked_content