blob: b17b0bdc3ee2e42c259eb39eed29ab6ed302bff0 [file] [log] [blame]
// Copyright 2017 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.
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_navigation_util_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_list.h"
#include "components/component_updater/pref_names.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/extension_system.h"
#include "ui/base/window_open_disposition.h"
namespace safe_browsing {
namespace {
// These values are used to send UMA information and are replicated in the
// histograms.xml file, so the order MUST NOT CHANGE.
enum PromptDialogResponseHistogramValue {
PROMPT_DIALOG_RESPONSE_ACCEPTED = 0,
PROMPT_DIALOG_RESPONSE_DETAILS = 1,
PROMPT_DIALOG_RESPONSE_CANCELLED = 2,
PROMPT_DIALOG_RESPONSE_DISMISSED = 3,
PROMPT_DIALOG_RESPONSE_CLOSED_WITHOUT_USER_INTERACTION = 4,
PROMPT_DIALOG_RESPONSE_MAX,
};
void RecordPromptDialogResponseHistogram(
PromptDialogResponseHistogramValue value) {
UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.PromptDialogResponse", value,
PROMPT_DIALOG_RESPONSE_MAX);
}
} // namespace
ChromeCleanerPromptDelegate::~ChromeCleanerPromptDelegate() = default;
class ChromeCleanerPromptDelegateImpl : public ChromeCleanerPromptDelegate {
public:
void ShowChromeCleanerPrompt(
Browser* browser,
ChromeCleanerDialogController* dialog_controller,
ChromeCleanerController* cleaner_controller) override {
chrome::ShowChromeCleanerPrompt(browser, dialog_controller,
cleaner_controller);
}
};
ChromeCleanerDialogControllerImpl::ChromeCleanerDialogControllerImpl(
ChromeCleanerController* cleaner_controller)
: cleaner_controller_(cleaner_controller),
prompt_delegate_impl_(
std::make_unique<ChromeCleanerPromptDelegateImpl>()) {
DCHECK(cleaner_controller_);
DCHECK_EQ(ChromeCleanerController::State::kScanning,
cleaner_controller_->state());
cleaner_controller_->AddObserver(this);
prompt_delegate_ = prompt_delegate_impl_.get();
}
ChromeCleanerDialogControllerImpl::~ChromeCleanerDialogControllerImpl() =
default;
void ChromeCleanerDialogControllerImpl::DialogShown() {
time_dialog_shown_ = base::Time::Now();
base::RecordAction(
base::UserMetricsAction("SoftwareReporter.PromptDialog_Shown"));
}
void ChromeCleanerDialogControllerImpl::Accept(bool logs_enabled) {
DCHECK(browser_);
RecordPromptDialogResponseHistogram(PROMPT_DIALOG_RESPONSE_ACCEPTED);
RecordCleanupStartedHistogram(CLEANUP_STARTED_FROM_PROMPT_DIALOG);
UMA_HISTOGRAM_LONG_TIMES_100(
"SoftwareReporter.PromptDialog.TimeUntilDone_Accepted",
base::Time::Now() - time_dialog_shown_);
base::RecordAction(
base::UserMetricsAction("SoftwareReporter.PromptDialog_Accepted"));
Profile* profile = browser_->profile();
extensions::ExtensionService* extension_service =
extensions::ExtensionSystem::Get(profile)->extension_service();
cleaner_controller_->ReplyWithUserResponse(
profile, extension_service,
logs_enabled
? ChromeCleanerController::UserResponse::kAcceptedWithLogs
: ChromeCleanerController::UserResponse::kAcceptedWithoutLogs);
chrome_cleaner_util::OpenCleanupPage(
browser_, WindowOpenDisposition::NEW_FOREGROUND_TAB);
OnInteractionDone();
}
void ChromeCleanerDialogControllerImpl::Cancel() {
DCHECK(browser_);
RecordPromptDialogResponseHistogram(PROMPT_DIALOG_RESPONSE_CANCELLED);
DCHECK(!time_dialog_shown_.is_null());
UMA_HISTOGRAM_LONG_TIMES_100(
"SoftwareReporter.PromptDialog.TimeUntilDone_Canceled",
base::Time::Now() - time_dialog_shown_);
base::RecordAction(
base::UserMetricsAction("SoftwareReporter.PromptDialog_Canceled"));
Profile* profile = browser_->profile();
extensions::ExtensionService* extension_service =
extensions::ExtensionSystem::Get(profile)->extension_service();
cleaner_controller_->ReplyWithUserResponse(
profile, extension_service,
ChromeCleanerController::UserResponse::kDenied);
OnInteractionDone();
}
void ChromeCleanerDialogControllerImpl::Close() {
DCHECK(browser_);
RecordPromptDialogResponseHistogram(PROMPT_DIALOG_RESPONSE_DISMISSED);
DCHECK(!time_dialog_shown_.is_null());
UMA_HISTOGRAM_LONG_TIMES_100(
"SoftwareReporter.PromptDialog.TimeUntilDone_Dismissed",
base::Time::Now() - time_dialog_shown_);
base::RecordAction(
base::UserMetricsAction("SoftwareReporter.PromptDialog_Dismissed"));
Profile* profile = browser_->profile();
extensions::ExtensionService* extension_service =
extensions::ExtensionSystem::Get(profile)->extension_service();
cleaner_controller_->ReplyWithUserResponse(
profile, extension_service,
ChromeCleanerController::UserResponse::kDismissed);
OnInteractionDone();
}
void ChromeCleanerDialogControllerImpl::ClosedWithoutUserInteraction() {
RecordPromptDialogResponseHistogram(
PROMPT_DIALOG_RESPONSE_CLOSED_WITHOUT_USER_INTERACTION);
base::RecordAction(base::UserMetricsAction(
"SoftwareReporter.PromptDialog_ClosedWithoutUserInteraction"));
OnInteractionDone();
}
void ChromeCleanerDialogControllerImpl::DetailsButtonClicked(
bool logs_enabled) {
RecordPromptDialogResponseHistogram(PROMPT_DIALOG_RESPONSE_DETAILS);
DCHECK(!time_dialog_shown_.is_null());
UMA_HISTOGRAM_LONG_TIMES_100(
"SoftwareReporter.PromptDialog.TimeUntilDone_DetailsButtonClicked",
base::Time::Now() - time_dialog_shown_);
base::RecordAction(base::UserMetricsAction(
"SoftwareReporter.PromptDialog_DetailsButtonClicked"));
cleaner_controller_->SetLogsEnabled(browser_->profile(), logs_enabled);
chrome_cleaner_util::OpenCleanupPage(
browser_, WindowOpenDisposition::NEW_FOREGROUND_TAB);
OnInteractionDone();
}
void ChromeCleanerDialogControllerImpl::SetLogsEnabled(bool logs_enabled) {
cleaner_controller_->SetLogsEnabled(browser_->profile(), logs_enabled);
if (logs_enabled) {
base::RecordAction(base::UserMetricsAction(
"SoftwareReporter.PromptDialog.LogsPermissionCheckbox_Enabled"));
} else {
base::RecordAction(base::UserMetricsAction(
"SoftwareReporter.PromptDialog.LogsPermissionCheckbox_Disabled"));
}
}
bool ChromeCleanerDialogControllerImpl::LogsEnabled() {
return cleaner_controller_->logs_enabled(browser_->profile());
}
bool ChromeCleanerDialogControllerImpl::LogsManaged() {
return cleaner_controller_->IsReportingManagedByPolicy(browser_->profile());
}
void ChromeCleanerDialogControllerImpl::OnIdle(
ChromeCleanerController::IdleReason idle_reason) {
if (!dialog_shown_)
OnInteractionDone();
}
void ChromeCleanerDialogControllerImpl::OnScanning() {
// This notification is received when the object is first added as an observer
// of cleaner_controller_.
DCHECK(!dialog_shown_);
// TODO(alito): Close the dialog in case it has been kept open until the next
// time the prompt is going to be shown. http://crbug.com/734689
}
void ChromeCleanerDialogControllerImpl::OnInfected(
bool is_powered_by_partner,
const ChromeCleanerScannerResults& reported_results) {
DCHECK(!dialog_shown_);
browser_ = chrome_cleaner_util::FindBrowser();
if (!browser_) {
RecordPromptNotShownWithReasonHistogram(
NO_PROMPT_REASON_WAITING_FOR_BROWSER);
prompt_pending_ = true;
BrowserList::AddObserver(this);
return;
}
ShowChromeCleanerPrompt();
RecordPromptShownWithTypeHistogram(
PromptTypeHistogramValue::PROMPT_TYPE_ON_TRANSITION_TO_INFECTED_STATE);
}
void ChromeCleanerDialogControllerImpl::OnCleaning(
bool is_powered_by_partner,
const ChromeCleanerScannerResults& reported_results) {
if (!dialog_shown_)
OnInteractionDone();
}
void ChromeCleanerDialogControllerImpl::OnRebootRequired() {
if (!dialog_shown_)
OnInteractionDone();
}
void ChromeCleanerDialogControllerImpl::OnBrowserSetLastActive(
Browser* browser) {
DCHECK(prompt_pending_);
DCHECK(browser);
DCHECK(!browser_);
browser_ = browser;
ShowChromeCleanerPrompt();
RecordPromptShownWithTypeHistogram(
PromptTypeHistogramValue::PROMPT_TYPE_ON_BROWSER_WINDOW_AVAILABLE);
prompt_pending_ = false;
BrowserList::RemoveObserver(this);
}
void ChromeCleanerDialogControllerImpl::SetPromptDelegateForTests(
ChromeCleanerPromptDelegate* delegate) {
prompt_delegate_ = delegate;
}
void ChromeCleanerDialogControllerImpl::ShowChromeCleanerPrompt() {
DCHECK(browser_);
Profile* profile = browser_->profile();
DCHECK(profile);
PrefService* prefs = profile->GetPrefs();
DCHECK(prefs);
// Don't show the prompt again if it's been shown before for this profile and
// for the current variations seed.
const std::string incoming_seed = GetIncomingSRTSeed();
const std::string old_seed = prefs->GetString(prefs::kSwReporterPromptSeed);
if (!incoming_seed.empty() && incoming_seed != old_seed)
prefs->SetString(prefs::kSwReporterPromptSeed, incoming_seed);
prompt_delegate_->ShowChromeCleanerPrompt(browser_, this,
cleaner_controller_);
dialog_shown_ = true;
}
void ChromeCleanerDialogControllerImpl::OnInteractionDone() {
if (prompt_pending_) {
BrowserList::RemoveObserver(this);
prompt_pending_ = false;
}
cleaner_controller_->RemoveObserver(this);
delete this;
}
} // namespace safe_browsing