// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_
#define ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_
#include <map>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/time/time.h"
namespace android_webview {
// Records how much of the screen is covered by WebViews. This helps us
// determine what WebView is being used for.
//
// Lifetime: Singleton
class VisibilityMetricsLogger {
public:
// These values are persisted to logs and must match the WebViewUrlScheme enum
// defined in enums.xml. Entries should not be renumbered and numeric values
// should never be reused.
enum class Scheme {
kEmpty = 0,
kUnknown = 1,
kHttp = 2,
kHttps = 3,
kFile = 4,
kFtp = 5,
kData = 6,
kJavaScript = 7,
kAbout = 8,
kChrome = 9,
kBlob = 10,
kContent = 11,
kIntent = 12,
kMaxValue = kIntent,
};
static Scheme SchemeStringToEnum(const std::string& scheme);
struct VisibilityInfo {
bool view_attached = false;
bool view_visible = false;
bool window_visible = false;
Scheme scheme = Scheme::kEmpty;
bool IsVisible() const;
};
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class Visibility {
kVisible = 0,
kNotVisible = 1,
kMaxValue = kNotVisible
};
class Client {
public:
virtual VisibilityInfo GetVisibilityInfo() = 0;
};
enum class ClientAction {
kAdded = 0,
kRemoved = 1,
kVisibilityChanged = 2,
kMaxValue = kVisibilityChanged,
};
VisibilityMetricsLogger();
virtual ~VisibilityMetricsLogger();
VisibilityMetricsLogger(const VisibilityMetricsLogger&) = delete;
VisibilityMetricsLogger& operator=(const VisibilityMetricsLogger&) = delete;
void AddClient(Client* client);
void RemoveClient(Client* client);
void ClientVisibilityChanged(Client* client);
void UpdateScreenCoverage(int global_percentage,
const std::vector<Scheme>& schemes,
const std::vector<int>& scheme_percentages);
void RecordMetrics();
// Set a callback that is executed when global visibility changes, i.e. when:
// - false => true: no client was visible and one becomes visible.
// - true => false: >=1 clients were visible and all became hidden.
using OnVisibilityChangedCallback =
base::RepeatingCallback<void(bool /*visible*/)>;
void SetOnVisibilityChangedCallback(OnVisibilityChangedCallback);
private:
void UpdateDurations();
void ProcessClientUpdate(Client* client,
const VisibilityInfo& info,
ClientAction action);
void RecordVisibilityMetrics();
void RecordVisibleSchemeMetrics();
void RecordScreenCoverageMetrics();
// Counts the number of visible clients.
size_t all_clients_visible_count_ = 0;
// Counts the number of visible clients per scheme.
size_t per_scheme_visible_counts_[static_cast<size_t>(Scheme::kMaxValue) +
1] = {};
struct WebViewDurationTracker {
// Duration any WebView meets the tracking criteria
base::TimeDelta any_webview_tracked_duration_ = base::Seconds(0);
// Duration no WebViews meet the tracking criteria
base::TimeDelta no_webview_tracked_duration_ = base::Seconds(0);
// Total duration that WebViews meet the tracking criteria (i.e. if
// 2x WebViews meet the criteria for 1 second then increment by 2 seconds)
base::TimeDelta per_webview_duration_ = base::Seconds(0);
// Total duration that WebViews exist but do not meet the tracking criteria
base::TimeDelta per_webview_untracked_duration_ = base::Seconds(0);
};
WebViewDurationTracker all_clients_tracker_;
WebViewDurationTracker
per_scheme_trackers_[static_cast<size_t>(Scheme::kMaxValue) + 1] = {};
base::TimeTicks last_update_time_;
std::map<Client*, VisibilityInfo> client_visibility_;
// The screen coverage percentage for all visible AwContents merged together.
int global_coverage_percentage_ = 0;
// The durations by screen coverage percentage for all visible AwContents
// merged together.
base::TimeDelta global_coverage_percentage_durations_[101] = {};
// The currently visible schemes and their screen coverage percentages. A
// scheme can occur more than once at a time so this uses a multimap.
std::multimap<Scheme, int> schemes_to_coverage_percentages_;
// The durations by screen coverage percentage and visible scheme.
std::map<Scheme, std::map<int, base::TimeDelta>>
schemes_to_percentages_to_durations_;
OnVisibilityChangedCallback on_visibility_changed_callback_;
};
} // namespace android_webview
#endif // ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_