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 
5 #ifndef CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SCORE_H_
6 #define CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SCORE_H_
7 
8 #include <memory>
9 
10 #include "base/macros.h"
11 #include "base/time/clock.h"
12 #include "base/values.h"
13 #include "chrome/browser/media/media_engagement_score_details.mojom.h"
14 #include "components/content_settings/core/browser/host_content_settings_map.h"
15 #include "url/origin.h"
16 
17 class HostContentSettingsMap;
18 
19 // Calculates and stores the Media Engagement Index score for a certain origin.
20 class MediaEngagementScore final {
21  public:
22   // The dictionary keys to store individual metrics. kVisitsKey will store the
23   // number of visits to an origin and kMediaPlaybacksKey will store the number
24   // of media playbacks on an origin. kLastMediaPlaybackTimeKey will store the
25   // timestamp of the last media playback on an origin. kHasHighScoreKey will
26   // store whether the score is considered high.
27   static const char kVisitsKey[];
28   static const char kMediaPlaybacksKey[];
29   static const char kLastMediaPlaybackTimeKey[];
30   static const char kHasHighScoreKey[];
31 
32   // Origins with a number of visits less than this number will recieve
33   // a score of zero.
34   static int GetScoreMinVisits();
35 
36   // The upper and lower threshold of whether the total score is considered
37   // to be high.
38   static double GetHighScoreLowerThreshold();
39   static double GetHighScoreUpperThreshold();
40 
41   MediaEngagementScore(base::Clock* clock,
42                        const url::Origin& origin,
43                        HostContentSettingsMap* settings);
44   ~MediaEngagementScore();
45 
46   MediaEngagementScore(MediaEngagementScore&&);
47   MediaEngagementScore& operator=(MediaEngagementScore&&);
48 
49   // Returns the total score, as per the formula.
actual_score()50   double actual_score() const { return actual_score_; }
51 
52   // Returns whether the total score is considered high.
high_score()53   bool high_score() const { return is_high_; }
54 
55   // Returns the origin associated with this score.
origin()56   const url::Origin& origin() const { return origin_; }
57 
58   // Writes the values in this score into |settings_map_|. If there are multiple
59   // instances of a score object for an origin, this could result in stale data
60   // being stored.
61   void Commit();
62 
63   // Get/increment the number of visits this origin has had.
visits()64   int visits() const { return visits_; }
IncrementVisits()65   void IncrementVisits() { SetVisits(visits() + 1); }
66 
67   // Get/increment the number of media playbacks this origin has had.
media_playbacks()68   int media_playbacks() const { return media_playbacks_; }
69   void IncrementMediaPlaybacks();
70 
71   // Gets/sets the last time media was played on this origin.
last_media_playback_time()72   base::Time last_media_playback_time() const {
73     return last_media_playback_time_;
74   }
set_last_media_playback_time(base::Time new_time)75   void set_last_media_playback_time(base::Time new_time) {
76     last_media_playback_time_ = new_time;
77   }
78 
79   // Get a breakdown of the score that can be serialized by Mojo.
80   media::mojom::MediaEngagementScoreDetailsPtr GetScoreDetails() const;
81 
82  protected:
83   friend class MediaEngagementAutoplayBrowserTest;
84   friend class MediaEngagementContentsObserverTest;
85   friend class MediaEngagementSessionTest;
86   friend class MediaEngagementService;
87 
88   // Only used by the Media Engagement service when bulk loading data.
89   MediaEngagementScore(base::Clock* clock,
90                        const url::Origin& origin,
91                        std::unique_ptr<base::DictionaryValue> score_dict,
92                        HostContentSettingsMap* settings);
93 
94   static const char kScoreMinVisitsParamName[];
95   static const char kHighScoreLowerThresholdParamName[];
96   static const char kHighScoreUpperThresholdParamName[];
97 
98   void SetVisits(int visits);
99   void SetMediaPlaybacks(int media_playbacks);
100 
101  private:
102   friend class MediaEngagementServiceTest;
103   friend class MediaEngagementScoreTest;
104 
105   // Update the dictionary continaing the latest score values and return whether
106   // they have changed or not (since what was last retrieved from content
107   // settings).
108   bool UpdateScoreDict();
109 
110   // If the number of playbacks or visits is updated then this will recalculate
111   // the total score and whether the score is considered high.
112   void Recalculate();
113 
114   // The number of media playbacks this origin has had.
115   int media_playbacks_ = 0;
116 
117   // The number of visits this origin has had.
118   int visits_ = 0;
119 
120   // If the current score is considered high.
121   bool is_high_ = false;
122 
123   // The current engagement score.
124   double actual_score_ = 0.0;
125 
126   // The last time media was played back on this origin.
127   base::Time last_media_playback_time_;
128 
129   // The origin this score represents.
130   url::Origin origin_;
131 
132   // A clock that can be used for testing, owned by the service.
133   base::Clock* clock_;
134 
135   // The dictionary that represents this engagement score.
136   std::unique_ptr<base::DictionaryValue> score_dict_;
137 
138   // The content settings map that will persist the score,
139   // has a lifetime of the Profile like the service which owns |this|.
140   HostContentSettingsMap* settings_map_ = nullptr;
141 
142   DISALLOW_COPY_AND_ASSIGN(MediaEngagementScore);
143 };
144 
145 #endif  // CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SCORE_H_
146