blob: c9471af59da1f31f948bd9d13efb36a1e4aa529c [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/web_applications/web_app_metrics.h"
#include <algorithm>
#include <optional>
#include <string>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/metrics/histogram_functions.h"
#include "base/observer_list.h"
#include "base/one_shot_event.h"
#include "base/power_monitor/power_monitor.h"
#include "base/task/sequenced_task_runner.h"
#include "build/build_config.h"
#include "chrome/browser/after_startup_task_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/browser/ui/web_applications/web_app_metrics_factory.h"
#include "chrome/browser/web_applications/proto/web_app_install_state.pb.h"
#include "chrome/browser/web_applications/web_app_constants.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_tab_helper.h"
#include "chrome/browser/web_applications/web_app_ui_manager.h"
#include "components/site_engagement/content/engagement_type.h"
#include "components/site_engagement/content/site_engagement_service.h"
#include "content/public/browser/web_contents.h"
namespace web_app {
namespace {
bool g_disable_automatic_icon_health_checks_for_testing = false;
void RecordEngagementHistogram(
const std::string& histogram_name,
site_engagement::EngagementType engagement_type) {
base::UmaHistogramEnumeration(histogram_name, engagement_type,
site_engagement::EngagementType::kLast);
}
void RecordTabOrWindowHistogram(
const std::string& histogram_prefix,
bool in_window,
site_engagement::EngagementType engagement_type) {
RecordEngagementHistogram(
histogram_prefix + (in_window ? ".InWindow" : ".InTab"), engagement_type);
}
} // namespace
// static
WebAppMetrics* WebAppMetrics::Get(Profile* profile) {
return WebAppMetricsFactory::GetForProfile(profile);
}
// static
void WebAppMetrics::DisableAutomaticIconHealthChecksForTesting() {
g_disable_automatic_icon_health_checks_for_testing = true;
}
WebAppMetrics::WebAppMetrics(Profile* profile)
: SiteEngagementObserver(
site_engagement::SiteEngagementService::Get(profile)),
profile_(profile),
icon_health_checks_(profile) {
if (!g_disable_automatic_icon_health_checks_for_testing) {
AfterStartupTaskUtils::PostTask(
FROM_HERE, base::SequencedTaskRunner::GetCurrentDefault(),
base::BindOnce(&WebAppIconHealthChecks::Start,
icon_health_checks_.GetWeakPtr(), base::DoNothing()));
}
WebAppProvider* provider = WebAppProvider::GetForLocalAppsUnchecked(profile_);
DCHECK(provider);
provider->on_registry_ready().Post(
FROM_HERE, base::BindOnce(&WebAppMetrics::CountUserInstalledApps,
weak_ptr_factory_.GetWeakPtr()));
}
WebAppMetrics::~WebAppMetrics() = default;
void WebAppMetrics::OnEngagementEvent(
content::WebContents* web_contents,
const GURL& url,
double score,
double old_score,
site_engagement::EngagementType engagement_type,
const std::optional<webapps::AppId>& app_id) {
if (!web_contents) {
return;
}
Browser* browser = chrome::FindBrowserWithTab(web_contents);
if (!browser) {
return;
}
// Number of apps is not yet counted.
if (num_user_installed_apps_ == kNumUserInstalledAppsNotCounted) {
return;
}
// The engagement broken down by the number of apps installed must be recorded
// for all engagement events, not just web apps.
if (num_user_installed_apps_ > 3) {
RecordEngagementHistogram(
"WebApp.Engagement.MoreThanThreeUserInstalledApps", engagement_type);
} else if (num_user_installed_apps_ > 0) {
RecordEngagementHistogram("WebApp.Engagement.UpToThreeUserInstalledApps",
engagement_type);
} else {
RecordEngagementHistogram("WebApp.Engagement.NoUserInstalledApps",
engagement_type);
}
if (!app_id) {
return;
}
CHECK(!app_id->empty());
// No HostedAppBrowserController if app is running as a tab in common browser.
const bool in_window = !!browser->app_controller();
WebAppRegistrar& registrar =
WebAppProvider::GetForLocalAppsUnchecked(profile_)->registrar_unsafe();
const bool user_installed = registrar.WasInstalledByUser(*app_id);
const bool is_diy_app = registrar.IsDiyApp(*app_id);
const bool is_default_installed =
registrar.IsInstalledByDefaultManagement(*app_id);
// Record all web apps:
RecordTabOrWindowHistogram("WebApp.Engagement", in_window, engagement_type);
if (user_installed) {
RecordTabOrWindowHistogram("WebApp.Engagement.UserInstalled", in_window,
engagement_type);
if (is_diy_app) {
RecordTabOrWindowHistogram("WebApp.Engagement.UserInstalled.Diy",
in_window, engagement_type);
} else {
RecordTabOrWindowHistogram("WebApp.Engagement.UserInstalled.Crafted",
in_window, engagement_type);
}
}
if (is_default_installed) {
// Record this app into more specific bucket if was installed by default:
RecordTabOrWindowHistogram("WebApp.Engagement.DefaultInstalled", in_window,
engagement_type);
}
}
void WebAppMetrics::CountUserInstalledAppsForTesting() {
// Reset and re-count.
num_user_installed_apps_ = kNumUserInstalledAppsNotCounted;
CountUserInstalledApps();
}
void WebAppMetrics::CountUserInstalledApps() {
DCHECK_EQ(kNumUserInstalledAppsNotCounted, num_user_installed_apps_);
WebAppProvider* provider = WebAppProvider::GetForLocalAppsUnchecked(profile_);
num_user_installed_apps_ =
provider->registrar_unsafe().CountUserInstalledApps();
DCHECK_NE(kNumUserInstalledAppsNotCounted, num_user_installed_apps_);
DCHECK_GE(num_user_installed_apps_, 0);
}
} // namespace web_app