1 // Copyright 2020 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 ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_
6 #define ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_
7 
8 #include <map>
9 
10 #include "base/callback.h"
11 #include "base/synchronization/lock.h"
12 #include "base/time/time.h"
13 
14 namespace base {
15 
16 class HistogramBase;
17 
18 }  // namespace base
19 
20 namespace android_webview {
21 
22 class VisibilityMetricsLogger {
23  public:
24   struct VisibilityInfo {
25     bool view_attached = false;
26     bool view_visible = false;
27     bool window_visible = false;
28     bool scheme_http_or_https = false;
29 
30     bool IsVisible() const;
31     bool ContainsOpenWebContent() const;
32     bool IsDisplayingOpenWebContent() const;
33   };
34 
35   // These values are persisted to logs. Entries should not be renumbered and
36   // numeric values should never be reused.
37   enum class Visibility {
38     kVisible = 0,
39     kNotVisible = 1,
40     kMaxValue = kNotVisible
41   };
42 
43   // These values are persisted to logs. Entries should not be renumbered and
44   // numeric values should never be reused.
45   enum class WebViewOpenWebScreenPortion {
46     kZeroPercent = 0,
47     kTenPercent = 1,
48     kTwentyPercent = 2,
49     kThirtyPercent = 3,
50     kFortyPercent = 4,
51     kFiftyPercent = 5,
52     kSixtyPercent = 6,
53     kSeventyPercent = 7,
54     kEightyPercent = 8,
55     kNinetyPercent = 9,
56     kOneHundredPercent = 10,
57     kMaxValue = kOneHundredPercent
58   };
59 
60   // These values are persisted to logs. Entries should not be renumbered and
61   // numeric values should never be reused.
62   enum class WebViewOpenWebVisibility {
63     kDisplayOpenWebContent = 0,
64     kNotDisplayOpenWebContent = 1,
65     kMaxValue = kNotDisplayOpenWebContent
66   };
67 
68   class Client {
69    public:
70     virtual VisibilityInfo GetVisibilityInfo() = 0;
71   };
72 
73   VisibilityMetricsLogger();
74   virtual ~VisibilityMetricsLogger();
75 
76   VisibilityMetricsLogger(const VisibilityMetricsLogger&) = delete;
77   VisibilityMetricsLogger& operator=(const VisibilityMetricsLogger&) = delete;
78 
79   void AddClient(Client* client);
80   void RemoveClient(Client* client);
81   void ClientVisibilityChanged(Client* client);
82   void UpdateOpenWebScreenArea(int pixels, int percentage);
83 
84   void RecordMetrics();
85 
86   // Set a callback that is executed when global visibility changes, i.e. when:
87   //  - false => true: no client was visible and one becomes visible.
88   //  - true => false: >=1 clients were visible and all became hidden.
89   using OnVisibilityChangedCallback =
90       base::RepeatingCallback<void(bool /*visible*/)>;
91   void SetOnVisibilityChangedCallback(OnVisibilityChangedCallback);
92 
93  private:
94   static base::HistogramBase* GetGlobalVisibilityHistogram();
95   static base::HistogramBase* GetPerWebViewVisibilityHistogram();
96   static base::HistogramBase* GetGlobalOpenWebVisibilityHistogram();
97   static base::HistogramBase* GetPerWebViewOpenWebVisibilityHistogram();
98   static base::HistogramBase* GetOpenWebVisibileScreenPortionHistogram();
99   static base::HistogramBase* CreateHistogramForDurationTracking(
100       const char* name,
101       int max_value);
102 
103   void UpdateDurations(base::TimeTicks update_time);
104   void ProcessClientUpdate(Client* client, const VisibilityInfo& info);
105   bool IsVisible(const VisibilityInfo& info);
106   bool IsDisplayingOpenWebContent(const VisibilityInfo& info);
107   void RecordVisibilityMetrics();
108   void RecordOpenWebDisplayMetrics();
109   void RecordScreenPortionMetrics();
110 
111   // Counter for visible clients
112   size_t visible_client_count_ = 0;
113   // Counter for visible web clients
114   size_t visible_webcontent_client_count_ = 0;
115 
116   struct WebViewDurationTracker {
117     // Duration any WebView meets the tracking criteria
118     base::TimeDelta any_webview_tracked_duration_ =
119         base::TimeDelta::FromSeconds(0);
120     // Duration no WebViews meet the tracking criteria
121     base::TimeDelta no_webview_tracked_duration_ =
122         base::TimeDelta::FromSeconds(0);
123     // Total duration that WebViews meet the tracking criteria (i.e. if
124     // 2x WebViews meet the criteria for 1 second then increment by 2 seconds)
125     base::TimeDelta per_webview_duration_ = base::TimeDelta::FromSeconds(0);
126     // Total duration that WebViews exist but do not meet the tracking criteria
127     base::TimeDelta per_webview_untracked_duration_ =
128         base::TimeDelta::FromSeconds(0);
129   };
130 
131   WebViewDurationTracker visible_duration_tracker_;
132   WebViewDurationTracker webcontent_visible_tracker_;
133 
134   base::TimeTicks last_update_time_;
135   std::map<Client*, VisibilityInfo> client_visibility_;
136 
137   int open_web_screen_area_pixels_ = 0;
138   int open_web_screen_area_percentage_ = 0;
139   WebViewOpenWebScreenPortion current_open_web_screen_portion_ =
140       WebViewOpenWebScreenPortion::kZeroPercent;
141   base::TimeDelta open_web_screen_portion_tracked_duration_
142       [static_cast<size_t>(WebViewOpenWebScreenPortion::kMaxValue) + 1] = {};
143 
144   OnVisibilityChangedCallback on_visibility_changed_callback_;
145 };
146 
147 }  // namespace android_webview
148 
149 #endif  // ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_
150