| // Copyright 2015 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. |
| |
| #ifndef CHROME_BROWSER_ENGAGEMENT_SITE_ENGAGEMENT_HELPER_H_ |
| #define CHROME_BROWSER_ENGAGEMENT_SITE_ENGAGEMENT_HELPER_H_ |
| |
| #include "base/macros.h" |
| #include "base/timer/timer.h" |
| #include "chrome/browser/engagement/site_engagement_service.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "content/public/browser/web_contents_user_data.h" |
| #include "third_party/WebKit/public/platform/site_engagement.mojom.h" |
| |
| class GURL; |
| |
| namespace content { |
| class NavigationHandle; |
| } |
| |
| namespace url { |
| class Origin; |
| } |
| |
| // Per-WebContents class to handle updating the site engagement scores for |
| // origins. |
| class SiteEngagementService::Helper |
| : public content::WebContentsObserver, |
| public content::WebContentsUserData<SiteEngagementService::Helper> { |
| public: |
| static void SetSecondsBetweenUserInputCheck(int seconds); |
| static void SetSecondsTrackingDelayAfterNavigation(int seconds); |
| static void SetSecondsTrackingDelayAfterShow(int seconds); |
| |
| ~Helper() override; |
| |
| void OnEngagementLevelChanged(const GURL& url, |
| blink::mojom::EngagementLevel level); |
| |
| private: |
| // Class to encapsulate the periodic detection of site engagement. |
| // |
| // Engagement detection begins at some constant time delta following |
| // navigation, tab activation, or media starting to play. Once engagement is |
| // recorded, detection is suspended for another constant time delta. For sites |
| // to continually record engagement, this overall design requires: |
| // |
| // 1. engagement at a non-trivial time after a site loads |
| // 2. continual engagement over a non-trivial duration of time |
| class PeriodicTracker { |
| public: |
| explicit PeriodicTracker(SiteEngagementService::Helper* helper); |
| virtual ~PeriodicTracker(); |
| |
| // Begin tracking after |initial_delay|. |
| void Start(base::TimeDelta initial_delay); |
| |
| // Pause tracking and restart after a delay. |
| void Pause(); |
| |
| // Stop tracking. |
| void Stop(); |
| |
| // Returns true if the timer is currently running. |
| bool IsTimerRunning(); |
| |
| // Set the timer object for testing. |
| void SetPauseTimerForTesting(std::unique_ptr<base::Timer> timer); |
| |
| SiteEngagementService::Helper* helper() { return helper_; } |
| |
| protected: |
| friend class SiteEngagementHelperTest; |
| |
| // Called when tracking is to be paused by |delay|. Used when tracking first |
| // starts or is paused. |
| void StartTimer(base::TimeDelta delay); |
| |
| // Called when the timer expires and engagement tracking is activated. |
| virtual void TrackingStarted() {} |
| |
| // Called when engagement tracking is paused or stopped. |
| virtual void TrackingStopped() {} |
| |
| private: |
| SiteEngagementService::Helper* helper_; |
| std::unique_ptr<base::Timer> pause_timer_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PeriodicTracker); |
| }; |
| |
| // Class to encapsulate time-on-site engagement detection. Time-on-site is |
| // recorded by detecting user input on a focused WebContents (mouse click, |
| // mouse wheel, keypress, or touch gesture tap) over time. |
| // |
| // After an initial delay, the input tracker begins listening to |
| // DidGetUserInteraction. When user input is signaled, site engagement is |
| // recorded, and the tracker sleeps for a delay period. |
| class InputTracker : public PeriodicTracker, |
| public content::WebContentsObserver { |
| public: |
| InputTracker(SiteEngagementService::Helper* helper, |
| content::WebContents* web_contents); |
| |
| bool is_tracking() const { return is_tracking_; } |
| |
| private: |
| friend class SiteEngagementHelperTest; |
| |
| void TrackingStarted() override; |
| void TrackingStopped() override; |
| |
| // Returns whether the tracker will respond to user input via |
| // DidGetUserInteraction. |
| bool is_tracking_; |
| |
| // content::WebContentsObserver overrides. |
| void DidGetUserInteraction(const blink::WebInputEvent::Type type) override; |
| |
| DISALLOW_COPY_AND_ASSIGN(InputTracker); |
| }; |
| |
| // Class to encapsulate media detection. Any media playing in a WebContents |
| // (focused or not) will accumulate engagement points. Media in a hidden |
| // WebContents will accumulate engagement more slowly than in an active |
| // WebContents. Media which has been muted will also accumulate engagement |
| // more slowly. |
| // |
| // When media begins playing in the main frame of a tab, the tracker is |
| // triggered with an initial delay. It then wakes up every |
| // |g_seconds_to_pause_engagement_detection| and notes the visible/hidden |
| // state of the tab, as well as whether media is still playing. |
| class MediaTracker : public PeriodicTracker, |
| public content::WebContentsObserver { |
| public: |
| MediaTracker(SiteEngagementService::Helper* helper, |
| content::WebContents* web_contents); |
| ~MediaTracker() override; |
| |
| private: |
| friend class SiteEngagementHelperTest; |
| |
| void TrackingStarted() override; |
| |
| // content::WebContentsObserver overrides. |
| void DidFinishNavigation(content::NavigationHandle* handle) override; |
| void MediaStartedPlaying(const MediaPlayerInfo& media_info, |
| const MediaPlayerId& id) override; |
| void MediaStoppedPlaying( |
| const MediaPlayerInfo& media_info, |
| const MediaPlayerId& id, |
| WebContentsObserver::MediaStoppedReason reason) override; |
| void WasShown() override; |
| void WasHidden() override; |
| |
| bool is_hidden_; |
| std::vector<MediaPlayerId> active_media_players_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MediaTracker); |
| }; |
| |
| explicit Helper(content::WebContents* web_contents); |
| friend class content::WebContentsUserData<SiteEngagementService::Helper>; |
| friend class SiteEngagementHelperTest; |
| |
| // Ask the SiteEngagementService to record engagement via user input at the |
| // current WebContents URL. |
| void RecordUserInput(SiteEngagementService::EngagementType type); |
| |
| // Ask the SiteEngagementService to record engagement via media playing at the |
| // current WebContents URL. |
| void RecordMediaPlaying(bool is_hidden); |
| |
| void SendEngagementLevelToFramesMatchingOrigin( |
| const url::Origin& origin, |
| blink::mojom::EngagementLevel level, |
| content::RenderFrameHost* render_frame_host); |
| void SendEngagementLevelToFrame(const url::Origin& origin, |
| blink::mojom::EngagementLevel level, |
| content::RenderFrameHost* render_frame_host); |
| |
| // content::WebContentsObserver overrides. |
| void DidFinishNavigation(content::NavigationHandle* handle) override; |
| void ReadyToCommitNavigation(content::NavigationHandle* handle) override; |
| void WasShown() override; |
| void WasHidden() override; |
| |
| InputTracker input_tracker_; |
| MediaTracker media_tracker_; |
| SiteEngagementService* service_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Helper); |
| }; |
| |
| #endif // CHROME_BROWSER_ENGAGEMENT_SITE_ENGAGEMENT_HELPER_H_ |