Commit 8825aab4 authored by Fabio Tirelo's avatar Fabio Tirelo Committed by Commit Bot

Chrome Cleaner UI: Add new reboot dialog prompt

This should be called when a cleanup ends in a reboot required state
and the Settings page is not the current active tab.

Bug: 770749
Change-Id: I3e81cc52e4973b767ce375647331dc51ae925d69
Reviewed-on: https://chromium-review.googlesource.com/695754
Commit-Queue: Fabio Tirelo <ftirelo@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarChris Sharp <csharp@chromium.org>
Reviewed-by: default avatarAli Tofigh <alito@chromium.org>
Cr-Commit-Position: refs/heads/master@{#510070}
parent 57f53584
...@@ -5823,6 +5823,12 @@ I don't think this site should be blocked! ...@@ -5823,6 +5823,12 @@ I don't think this site should be blocked!
<message name="IDS_CHROME_CLEANUP_PROMPT_TITLE" desc="Title of the Chrome Cleanup dialog. Chrome browser shows the dialog when unwanted software, like ad injectors or software that changes the user's settings without their knowledge, is found on the user's computer. Appears above a description of what the cleanup dialog does, along with a 'Remove', 'Cancel', and 'Details' button. 'Remove' is imperative, asking the user, do you want Chrome to remove harmful software?"> <message name="IDS_CHROME_CLEANUP_PROMPT_TITLE" desc="Title of the Chrome Cleanup dialog. Chrome browser shows the dialog when unwanted software, like ad injectors or software that changes the user's settings without their knowledge, is found on the user's computer. Appears above a description of what the cleanup dialog does, along with a 'Remove', 'Cancel', and 'Details' button. 'Remove' is imperative, asking the user, do you want Chrome to remove harmful software?">
Remove harmful software? Remove harmful software?
</message> </message>
<message name="IDS_CHROME_CLEANUP_REBOOT_PROMPT_TITLE" desc="Title of the Chrome Cleanup reboot prompt dialog. Chrome browser shows the dialog when the user runs the Chrome Cleanup tool and computer restart is required to finish the cleanup. User must take additional action to finish the cleanup. 'Restart' is imperative.">
To finish removing harmful software, restart your computer
</message>
<message name="IDS_CHROME_CLEANUP_REBOOT_PROMPT_RESTART_BUTTON_LABEL" desc="A button in the Chrome Cleanup reboot prompt dialog. Clicking this button causes the user's computer to turn off (shut down) and turn back on again. Imperative.">
Restart computer
</message>
<message name="IDS_CHROME_CLEANUP_WEBUI_DONE_BUTTON_LABEL" desc="A button on the web page for Chrome Cleanup. Clicking this button causes the card on the settings page to be dismissed."> <message name="IDS_CHROME_CLEANUP_WEBUI_DONE_BUTTON_LABEL" desc="A button on the web page for Chrome Cleanup. Clicking this button causes the card on the settings page to be dismissed.">
Done Done
</message> </message>
......
...@@ -20,6 +20,9 @@ static_library("safe_browsing") { ...@@ -20,6 +20,9 @@ static_library("safe_browsing") {
"chrome_cleaner/chrome_cleaner_fetcher_win.h", "chrome_cleaner/chrome_cleaner_fetcher_win.h",
"chrome_cleaner/chrome_cleaner_navigation_util_win.cc", "chrome_cleaner/chrome_cleaner_navigation_util_win.cc",
"chrome_cleaner/chrome_cleaner_navigation_util_win.h", "chrome_cleaner/chrome_cleaner_navigation_util_win.h",
"chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_win.cc",
"chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_win.h",
"chrome_cleaner/chrome_cleaner_reboot_dialog_controller_win.h",
"chrome_cleaner/chrome_cleaner_runner_win.cc", "chrome_cleaner/chrome_cleaner_runner_win.cc",
"chrome_cleaner/chrome_cleaner_runner_win.h", "chrome_cleaner/chrome_cleaner_runner_win.h",
"chrome_cleaner/chrome_cleaner_state_change_observer_win.cc", "chrome_cleaner/chrome_cleaner_state_change_observer_win.cc",
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_fetcher_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_fetcher_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_navigation_util_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_navigation_util_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_runner_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_runner_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/settings_resetter_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/settings_resetter_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.h"
...@@ -78,16 +79,6 @@ enum IPCDisconnectedHistogramValue { ...@@ -78,16 +79,6 @@ enum IPCDisconnectedHistogramValue {
IPC_DISCONNECTED_MAX, IPC_DISCONNECTED_MAX,
}; };
// These values are used to send UMA information and are replicated in the
// enums.xml, so the order MUST NOT CHANGE
enum SettingsPageActiveOnRebootRequiredHistogramValue {
SETTINGS_PAGE_ON_REBOOT_REQUIRED_NO_BROWSER = 0,
SETTINGS_PAGE_ON_REBOOT_REQUIRED_NOT_ACTIVE_TAB = 1,
SETTINGS_PAGE_ON_REBOOT_REQUIRED_ACTIVE_TAB = 2,
SETTINGS_PAGE_ON_REBOOT_REQUIRED_MAX,
};
// Attempts to change the Chrome Cleaner binary's suffix to ".exe". Will return // Attempts to change the Chrome Cleaner binary's suffix to ".exe". Will return
// an empty FilePath on failure. Should be called on a sequence with traits // an empty FilePath on failure. Should be called on a sequence with traits
// appropriate for IO operations. // appropriate for IO operations.
...@@ -153,13 +144,6 @@ void RecordIPCDisconnectedHistogram(IPCDisconnectedHistogramValue error) { ...@@ -153,13 +144,6 @@ void RecordIPCDisconnectedHistogram(IPCDisconnectedHistogramValue error) {
IPC_DISCONNECTED_MAX); IPC_DISCONNECTED_MAX);
} }
void RecordSettingsPageActiveOnRebootRequired(
SettingsPageActiveOnRebootRequiredHistogramValue value) {
UMA_HISTOGRAM_ENUMERATION(
"SoftwareReporter.Cleaner.SettingsPageActiveOnRebootRequired", value,
SETTINGS_PAGE_ON_REBOOT_REQUIRED_MAX);
}
} // namespace } // namespace
void RecordCleanupStartedHistogram(CleanupStartedHistogramValue value) { void RecordCleanupStartedHistogram(CleanupStartedHistogramValue value) {
...@@ -196,6 +180,12 @@ void ChromeCleanerControllerDelegate::ResetTaggedProfiles( ...@@ -196,6 +180,12 @@ void ChromeCleanerControllerDelegate::ResetTaggedProfiles(
} }
} }
void ChromeCleanerControllerDelegate::StartRebootPromptFlow(
ChromeCleanerController* controller) {
// The controller object decides if and when a prompt should be shown.
ChromeCleanerRebootDialogControllerImpl::Create(controller);
}
// static // static
ChromeCleanerControllerImpl* ChromeCleanerControllerImpl::GetInstance() { ChromeCleanerControllerImpl* ChromeCleanerControllerImpl::GetInstance() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -575,26 +565,8 @@ void ChromeCleanerControllerImpl::OnCleanerProcessDone( ...@@ -575,26 +565,8 @@ void ChromeCleanerControllerImpl::OnCleanerProcessDone(
RecordCleanupResultHistogram(CLEANUP_RESULT_REBOOT_REQUIRED); RecordCleanupResultHistogram(CLEANUP_RESULT_REBOOT_REQUIRED);
SetStateAndNotifyObservers(State::kRebootRequired); SetStateAndNotifyObservers(State::kRebootRequired);
Browser* browser = chrome_cleaner_util::FindBrowser(); // Start the reboot prompt flow.
if (!browser) { delegate_->StartRebootPromptFlow(this);
RecordSettingsPageActiveOnRebootRequired(
SETTINGS_PAGE_ON_REBOOT_REQUIRED_NO_BROWSER);
return;
}
// No need to reopen the Settings page if it's the current active tab.
if (chrome_cleaner_util::SettingsPageIsActiveTab(browser)) {
RecordSettingsPageActiveOnRebootRequired(
SETTINGS_PAGE_ON_REBOOT_REQUIRED_ACTIVE_TAB);
return;
}
// Reopens the Settings page as a background tab. Eventually the user
// might see that a reboot is required.
RecordSettingsPageActiveOnRebootRequired(
SETTINGS_PAGE_ON_REBOOT_REQUIRED_NOT_ACTIVE_TAB);
chrome_cleaner_util::OpenSettingsPage(
browser, WindowOpenDisposition::NEW_BACKGROUND_TAB);
return; return;
} }
......
...@@ -39,6 +39,9 @@ class ChromeCleanerControllerDelegate { ...@@ -39,6 +39,9 @@ class ChromeCleanerControllerDelegate {
virtual void TagForResetting(Profile* profile); virtual void TagForResetting(Profile* profile);
virtual void ResetTaggedProfiles(std::vector<Profile*> profiles, virtual void ResetTaggedProfiles(std::vector<Profile*> profiles,
base::OnceClosure continuation); base::OnceClosure continuation);
// Starts the reboot prompt flow if a cleanup requires a machine restart.
virtual void StartRebootPromptFlow(ChromeCleanerController* controller);
}; };
class ChromeCleanerControllerImpl : public ChromeCleanerController { class ChromeCleanerControllerImpl : public ChromeCleanerController {
......
...@@ -139,6 +139,10 @@ class ChromeCleanerControllerSimpleTest ...@@ -139,6 +139,10 @@ class ChromeCleanerControllerSimpleTest
FAIL(); FAIL();
} }
void StartRebootPromptFlow(ChromeCleanerController* controller) override {
FAIL();
}
// ChromeCleanerRunnerTestDelegate overrides. // ChromeCleanerRunnerTestDelegate overrides.
base::Process LaunchTestProcess( base::Process LaunchTestProcess(
...@@ -290,6 +294,10 @@ class ChromeCleanerControllerTest ...@@ -290,6 +294,10 @@ class ChromeCleanerControllerTest
std::move(continuation).Run(); std::move(continuation).Run();
} }
void StartRebootPromptFlow(ChromeCleanerController* controller) override {
reboot_flow_started_ = true;
}
// ChromeCleanerRunnerTestDelegate overrides. // ChromeCleanerRunnerTestDelegate overrides.
base::Process LaunchTestProcess( base::Process LaunchTestProcess(
...@@ -325,8 +333,7 @@ class ChromeCleanerControllerTest ...@@ -325,8 +333,7 @@ class ChromeCleanerControllerTest
if (process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess && if (process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess &&
crash_point_ == CrashPoint::kNone && crash_point_ == CrashPoint::kNone &&
uws_found_status_ == UwsFoundStatus::kUwsFoundRebootRequired && uws_found_status_ == UwsFoundStatus::kUwsFoundRebootRequired &&
(user_response_ == UserResponse::kAcceptedWithLogs || ExpectedPromptAccepted()) {
user_response_ == UserResponse::kAcceptedWithoutLogs)) {
return State::kRebootRequired; return State::kRebootRequired;
} }
return State::kIdle; return State::kIdle;
...@@ -344,8 +351,7 @@ class ChromeCleanerControllerTest ...@@ -344,8 +351,7 @@ class ChromeCleanerControllerTest
bool ExpectedOnCleaningCalled() { bool ExpectedOnCleaningCalled() {
return ExpectedOnInfectedCalled() && return ExpectedOnInfectedCalled() &&
crash_point_ != CrashPoint::kAfterRequestSent && crash_point_ != CrashPoint::kAfterRequestSent &&
(user_response_ == UserResponse::kAcceptedWithLogs || ExpectedPromptAccepted();
user_response_ == UserResponse::kAcceptedWithoutLogs);
} }
bool ExpectedOnRebootRequiredCalled() { bool ExpectedOnRebootRequiredCalled() {
...@@ -354,22 +360,25 @@ class ChromeCleanerControllerTest ...@@ -354,22 +360,25 @@ class ChromeCleanerControllerTest
bool ExpectedUwsFound() { return ExpectedOnInfectedCalled(); } bool ExpectedUwsFound() { return ExpectedOnInfectedCalled(); }
bool ExpectedPromptAccepted() {
return user_response_ == UserResponse::kAcceptedWithLogs ||
user_response_ == UserResponse::kAcceptedWithoutLogs;
}
bool ExpectedToTagProfile() { bool ExpectedToTagProfile() {
return process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess && return process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess &&
(crash_point_ == CrashPoint::kNone || (crash_point_ == CrashPoint::kNone ||
crash_point_ == CrashPoint::kAfterResponseReceived) && crash_point_ == CrashPoint::kAfterResponseReceived) &&
(uws_found_status_ == UwsFoundStatus::kUwsFoundNoRebootRequired || (uws_found_status_ == UwsFoundStatus::kUwsFoundNoRebootRequired ||
uws_found_status_ == UwsFoundStatus::kUwsFoundRebootRequired) && uws_found_status_ == UwsFoundStatus::kUwsFoundRebootRequired) &&
(user_response_ == UserResponse::kAcceptedWithLogs || ExpectedPromptAccepted();
user_response_ == UserResponse::kAcceptedWithoutLogs);
} }
bool ExpectedToResetSettings() { bool ExpectedToResetSettings() {
return process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess && return process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess &&
crash_point_ == CrashPoint::kNone && crash_point_ == CrashPoint::kNone &&
uws_found_status_ == UwsFoundStatus::kUwsFoundNoRebootRequired && uws_found_status_ == UwsFoundStatus::kUwsFoundNoRebootRequired &&
(user_response_ == UserResponse::kAcceptedWithLogs || ExpectedPromptAccepted();
user_response_ == UserResponse::kAcceptedWithoutLogs);
} }
ChromeCleanerController::IdleReason ExpectedIdleReason() { ChromeCleanerController::IdleReason ExpectedIdleReason() {
...@@ -390,9 +399,7 @@ class ChromeCleanerControllerTest ...@@ -390,9 +399,7 @@ class ChromeCleanerControllerTest
return IdleReason::kUserDeclinedCleanup; return IdleReason::kUserDeclinedCleanup;
} }
if (ExpectedOnInfectedCalled() && if (ExpectedOnInfectedCalled() && ExpectedPromptAccepted() &&
(user_response_ == UserResponse::kAcceptedWithLogs ||
user_response_ == UserResponse::kAcceptedWithoutLogs) &&
crash_point_ == CrashPoint::kAfterResponseReceived) { crash_point_ == CrashPoint::kAfterResponseReceived) {
return IdleReason::kCleaningFailed; return IdleReason::kCleaningFailed;
} }
...@@ -400,6 +407,13 @@ class ChromeCleanerControllerTest ...@@ -400,6 +407,13 @@ class ChromeCleanerControllerTest
return IdleReason::kCleaningSucceeded; return IdleReason::kCleaningSucceeded;
} }
bool ExpectedRebootFlowStarted() {
return process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess &&
crash_point_ == CrashPoint::kNone &&
uws_found_status_ == UwsFoundStatus::kUwsFoundRebootRequired &&
ExpectedPromptAccepted();
}
protected: protected:
// We need this because we need UI and IO threads during tests. The thread // We need this because we need UI and IO threads during tests. The thread
// bundle should be the first member of the class so that it will be destroyed // bundle should be the first member of the class so that it will be destroyed
...@@ -420,6 +434,8 @@ class ChromeCleanerControllerTest ...@@ -420,6 +434,8 @@ class ChromeCleanerControllerTest
std::vector<Profile*> profiles_tagged_; std::vector<Profile*> profiles_tagged_;
std::vector<Profile*> profiles_to_reset_if_tagged_; std::vector<Profile*> profiles_to_reset_if_tagged_;
bool reboot_flow_started_ = false;
}; };
MULTIPROCESS_TEST_MAIN(MockChromeCleanerProcessMain) { MULTIPROCESS_TEST_MAIN(MockChromeCleanerProcessMain) {
...@@ -522,6 +538,8 @@ TEST_P(ChromeCleanerControllerTest, WithMockCleanerProcess) { ...@@ -522,6 +538,8 @@ TEST_P(ChromeCleanerControllerTest, WithMockCleanerProcess) {
EXPECT_EQ(files_to_delete_on_infected, files_to_delete_on_cleaning); EXPECT_EQ(files_to_delete_on_infected, files_to_delete_on_cleaning);
} }
EXPECT_EQ(ExpectedRebootFlowStarted(), reboot_flow_started_);
std::vector<Profile*> expected_tagged; std::vector<Profile*> expected_tagged;
if (ExpectedToTagProfile()) if (ExpectedToTagProfile())
expected_tagged.push_back(profile1); expected_tagged.push_back(profile1);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_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.h"
#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_finder.h"
...@@ -41,23 +42,6 @@ class MockChromeCleanerPromptDelegate : public ChromeCleanerPromptDelegate { ...@@ -41,23 +42,6 @@ class MockChromeCleanerPromptDelegate : public ChromeCleanerPromptDelegate {
ChromeCleanerController* cleaner_controller)); ChromeCleanerController* cleaner_controller));
}; };
class MockChromeCleanerController
: public safe_browsing::ChromeCleanerController {
public:
MOCK_METHOD0(ShouldShowCleanupInSettingsUI, bool());
MOCK_METHOD0(IsPoweredByPartner, bool());
MOCK_CONST_METHOD0(state, State());
MOCK_CONST_METHOD0(idle_reason, IdleReason());
MOCK_METHOD1(SetLogsEnabled, void(bool));
MOCK_CONST_METHOD0(logs_enabled, bool());
MOCK_METHOD0(ResetIdleState, void());
MOCK_METHOD1(AddObserver, void(Observer*));
MOCK_METHOD1(RemoveObserver, void(Observer*));
MOCK_METHOD1(Scan, void(const safe_browsing::SwReporterInvocation&));
MOCK_METHOD2(ReplyWithUserResponse, void(Profile*, UserResponse));
MOCK_METHOD0(Reboot, void());
};
// Parameters for this test: // Parameters for this test:
// - const char* old_seed_: The old "Seed" Finch parameter saved in prefs. // - const char* old_seed_: The old "Seed" Finch parameter saved in prefs.
// - const char* incoming_seed_: The new "Seed" Finch parameter. // - const char* incoming_seed_: The new "Seed" Finch parameter.
......
...@@ -21,11 +21,6 @@ namespace safe_browsing { ...@@ -21,11 +21,6 @@ namespace safe_browsing {
namespace { namespace {
void OpenSettingsPage(Browser* browser) {
chrome_cleaner_util::OpenSettingsPage(
browser, WindowOpenDisposition::NEW_FOREGROUND_TAB);
}
// These values are used to send UMA information and are replicated in the // These values are used to send UMA information and are replicated in the
// histograms.xml file, so the order MUST NOT CHANGE. // histograms.xml file, so the order MUST NOT CHANGE.
enum PromptDialogResponseHistogramValue { enum PromptDialogResponseHistogramValue {
...@@ -97,7 +92,8 @@ void ChromeCleanerDialogControllerImpl::Accept(bool logs_enabled) { ...@@ -97,7 +92,8 @@ void ChromeCleanerDialogControllerImpl::Accept(bool logs_enabled) {
logs_enabled logs_enabled
? ChromeCleanerController::UserResponse::kAcceptedWithLogs ? ChromeCleanerController::UserResponse::kAcceptedWithLogs
: ChromeCleanerController::UserResponse::kAcceptedWithoutLogs); : ChromeCleanerController::UserResponse::kAcceptedWithoutLogs);
OpenSettingsPage(browser_); chrome_cleaner_util::OpenSettingsPage(
browser_, WindowOpenDisposition::NEW_FOREGROUND_TAB);
OnInteractionDone(); OnInteractionDone();
} }
...@@ -152,7 +148,8 @@ void ChromeCleanerDialogControllerImpl::DetailsButtonClicked( ...@@ -152,7 +148,8 @@ void ChromeCleanerDialogControllerImpl::DetailsButtonClicked(
"SoftwareReporter.PromptDialog_DetailsButtonClicked")); "SoftwareReporter.PromptDialog_DetailsButtonClicked"));
cleaner_controller_->SetLogsEnabled(logs_enabled); cleaner_controller_->SetLogsEnabled(logs_enabled);
OpenSettingsPage(browser_); chrome_cleaner_util::OpenSettingsPage(
browser_, WindowOpenDisposition::NEW_FOREGROUND_TAB);
OnInteractionDone(); OnInteractionDone();
} }
......
...@@ -22,8 +22,9 @@ Browser* FindBrowser() { ...@@ -22,8 +22,9 @@ Browser* FindBrowser() {
++browser_iterator) { ++browser_iterator) {
Browser* browser = *browser_iterator; Browser* browser = *browser_iterator;
if (browser->is_type_tabbed() && if (browser->is_type_tabbed() &&
(browser->window()->IsActive() || !browser->window()->IsMinimized())) (browser->window()->IsActive() || !browser->window()->IsMinimized())) {
return browser; return browser;
}
} }
return nullptr; return nullptr;
......
// 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_reboot_dialog_controller_impl_win.h"
#include <memory>
#include "base/memory/ptr_util.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_navigation_util_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace safe_browsing {
namespace {
using ::testing::_;
using ::testing::StrictMock;
using ::testing::Return;
class MockPromptDelegate
: public ChromeCleanerRebootDialogControllerImpl::PromptDelegate {
public:
MOCK_METHOD2(ShowChromeCleanerRebootPrompt,
void(Browser* browser,
ChromeCleanerRebootDialogControllerImpl* controller));
MOCK_METHOD1(OpenSettingsPage, void(Browser* browser));
};
// Parameters for this test:
// - bool reboot_dialog_enabled_: if kRebootPromptDialogFeature is enabled.
class ChromeCleanerRebootFlowTest : public InProcessBrowserTest,
public ::testing::WithParamInterface<bool> {
public:
ChromeCleanerRebootFlowTest() { reboot_dialog_enabled_ = GetParam(); }
void SetUpInProcessBrowserTestFixture() override {
if (reboot_dialog_enabled_)
scoped_feature_list_.InitAndEnableFeature(kRebootPromptDialogFeature);
else
scoped_feature_list_.InitAndDisableFeature(kRebootPromptDialogFeature);
// The implementation of dialog_controller may check state, and we are not
// interested in ensuring how many times this is done, since it's not part
// of the main functionality.
EXPECT_CALL(mock_cleaner_controller_, state())
.WillRepeatedly(
Return(ChromeCleanerController::State::kRebootRequired));
}
protected:
bool reboot_dialog_enabled_ = false;
StrictMock<MockChromeCleanerController> mock_cleaner_controller_;
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(ChromeCleanerRebootFlowTest,
OnRebootRequired_SettingsPageActive) {
ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUISettingsURL));
ASSERT_TRUE(chrome_cleaner_util::SettingsPageIsActiveTab(browser()));
ChromeCleanerRebootDialogControllerImpl::Create(
&mock_cleaner_controller_,
base::MakeUnique<StrictMock<MockPromptDelegate>>());
// StrictMock ensures no method for mock_prompt_delegate_ is called, and so
// neither a new tab nor the prompt dialog is opened.
}
IN_PROC_BROWSER_TEST_P(ChromeCleanerRebootFlowTest,
OnRebootRequired_SettingsPageNotActive) {
auto mock_prompt_delegate =
base::MakeUnique<StrictMock<MockPromptDelegate>>();
bool close_required = false;
if (reboot_dialog_enabled_) {
EXPECT_CALL(*mock_prompt_delegate, ShowChromeCleanerRebootPrompt(_, _))
.Times(1);
// If the prompt dialog is shown, the controller object will only be
// destroyed after user interaction. This will force the object to be
// deleted when the test ends.
close_required = true;
} else {
EXPECT_CALL(*mock_prompt_delegate, OpenSettingsPage(_)).Times(1);
}
ChromeCleanerRebootDialogControllerImpl* dialog_controller =
ChromeCleanerRebootDialogControllerImpl::Create(
&mock_cleaner_controller_, std::move(mock_prompt_delegate));
// Force interaction with the prompt to force deleting |dialog_controller|.
if (close_required)
dialog_controller->Close();
}
INSTANTIATE_TEST_CASE_P(AllTests,
ChromeCleanerRebootFlowTest,
::testing::Bool());
class ChromeCleanerRebootDialogResponseTest : public InProcessBrowserTest {
public:
void SetUpInProcessBrowserTestFixture() override {
scoped_feature_list_.InitAndEnableFeature(kRebootPromptDialogFeature);
// The implementation of dialog_controller may check state, and we are not
// interested in ensuring how many times this is done, since it's not part
// of the main functionality.
EXPECT_CALL(mock_cleaner_controller_, state())
.WillRepeatedly(
Return(ChromeCleanerController::State::kRebootRequired));
}
ChromeCleanerRebootDialogControllerImpl* dialog_controller() {
auto mock_prompt_delegate =
base::MakeUnique<StrictMock<MockPromptDelegate>>();
EXPECT_CALL(*mock_prompt_delegate, ShowChromeCleanerRebootPrompt(_, _))
.Times(1);
return ChromeCleanerRebootDialogControllerImpl::Create(
&mock_cleaner_controller_, std::move(mock_prompt_delegate));
}
protected:
StrictMock<MockChromeCleanerController> mock_cleaner_controller_;
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(ChromeCleanerRebootDialogResponseTest, Accept) {
EXPECT_CALL(mock_cleaner_controller_, Reboot());
dialog_controller()->Accept();
}
IN_PROC_BROWSER_TEST_F(ChromeCleanerRebootDialogResponseTest, Cancel) {
dialog_controller()->Cancel();
}
IN_PROC_BROWSER_TEST_F(ChromeCleanerRebootDialogResponseTest, Close) {
dialog_controller()->Close();
}
} // namespace
} // namespace safe_browsing
// 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_reboot_dialog_controller_impl_win.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.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 "content/public/browser/browser_thread.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
// enums.xml, so the order MUST NOT CHANGE
enum SettingsPageActiveOnRebootRequiredHistogramValue {
SETTINGS_PAGE_ON_REBOOT_REQUIRED_NO_BROWSER = 0,
SETTINGS_PAGE_ON_REBOOT_REQUIRED_NOT_ACTIVE_TAB = 1,
SETTINGS_PAGE_ON_REBOOT_REQUIRED_ACTIVE_TAB = 2,
SETTINGS_PAGE_ON_REBOOT_REQUIRED_MAX,
};
class PromptDelegateImpl
: public ChromeCleanerRebootDialogControllerImpl::PromptDelegate {
public:
void ShowChromeCleanerRebootPrompt(
Browser* browser,
ChromeCleanerRebootDialogControllerImpl* controller) override;
void OpenSettingsPage(Browser* browser) override;
};
void PromptDelegateImpl::ShowChromeCleanerRebootPrompt(
Browser* browser,
ChromeCleanerRebootDialogControllerImpl* controller) {
DCHECK(browser);
DCHECK(controller);
chrome::ShowChromeCleanerRebootPrompt(browser, controller);
}
void PromptDelegateImpl::OpenSettingsPage(Browser* browser) {
DCHECK(browser);
chrome_cleaner_util::OpenSettingsPage(
browser, WindowOpenDisposition::NEW_BACKGROUND_TAB);
}
void RecordSettingsPageActiveOnRebootRequired(
SettingsPageActiveOnRebootRequiredHistogramValue value) {
UMA_HISTOGRAM_ENUMERATION(
"SoftwareReporter.Cleaner.SettingsPageActiveOnRebootRequired", value,
SETTINGS_PAGE_ON_REBOOT_REQUIRED_MAX);
}
} // namespace
ChromeCleanerRebootDialogControllerImpl::PromptDelegate::~PromptDelegate() =
default;
// static
ChromeCleanerRebootDialogControllerImpl*
ChromeCleanerRebootDialogControllerImpl::Create(
ChromeCleanerController* cleaner_controller) {
return Create(cleaner_controller, base::MakeUnique<PromptDelegateImpl>());
}
// static
ChromeCleanerRebootDialogControllerImpl*
ChromeCleanerRebootDialogControllerImpl::Create(
ChromeCleanerController* cleaner_controller,
std::unique_ptr<PromptDelegate> prompt_delegate) {
ChromeCleanerRebootDialogControllerImpl* controller =
new ChromeCleanerRebootDialogControllerImpl(cleaner_controller,
std::move(prompt_delegate));
controller->MaybeStartRebootPrompt();
return controller;
}
void ChromeCleanerRebootDialogControllerImpl::DialogShown() {
DCHECK(base::FeatureList::IsEnabled(kRebootPromptDialogFeature));
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(crbug.com/770749) Collect metrics on how many times this dialog is
// shown.
}
void ChromeCleanerRebootDialogControllerImpl::Accept() {
DCHECK(base::FeatureList::IsEnabled(kRebootPromptDialogFeature));
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
cleaner_controller_->Reboot();
// If reboot fails, we don't want this object to continue existing.
OnInteractionDone();
}
void ChromeCleanerRebootDialogControllerImpl::Cancel() {
DCHECK(base::FeatureList::IsEnabled(kRebootPromptDialogFeature));
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
OnInteractionDone();
}
void ChromeCleanerRebootDialogControllerImpl::Close() {
DCHECK(base::FeatureList::IsEnabled(kRebootPromptDialogFeature));
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
OnInteractionDone();
}
ChromeCleanerRebootDialogControllerImpl::
ChromeCleanerRebootDialogControllerImpl(
ChromeCleanerController* cleaner_controller,
std::unique_ptr<PromptDelegate> prompt_delegate)
: cleaner_controller_(cleaner_controller),
prompt_delegate_(std::move(prompt_delegate)) {
DCHECK(cleaner_controller_);
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK_EQ(ChromeCleanerController::State::kRebootRequired,
cleaner_controller_->state());
}
ChromeCleanerRebootDialogControllerImpl::
~ChromeCleanerRebootDialogControllerImpl() = default;
void ChromeCleanerRebootDialogControllerImpl::MaybeStartRebootPrompt() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Browser* browser = chrome_cleaner_util::FindBrowser();
if (browser == nullptr) {
RecordSettingsPageActiveOnRebootRequired(
SETTINGS_PAGE_ON_REBOOT_REQUIRED_NO_BROWSER);
// TODO(crbug.com/770749) Register to decide if a prompt should be shown
// once a window becomes available.
OnInteractionDone();
return;
}
StartRebootPromptForBrowser(browser);
}
void ChromeCleanerRebootDialogControllerImpl::StartRebootPromptForBrowser(
Browser* browser) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (chrome_cleaner_util::SettingsPageIsActiveTab(browser)) {
RecordSettingsPageActiveOnRebootRequired(
SETTINGS_PAGE_ON_REBOOT_REQUIRED_ACTIVE_TAB);
OnInteractionDone();
return;
}
RecordSettingsPageActiveOnRebootRequired(
SETTINGS_PAGE_ON_REBOOT_REQUIRED_NOT_ACTIVE_TAB);
if (base::FeatureList::IsEnabled(kRebootPromptDialogFeature)) {
prompt_delegate_->ShowChromeCleanerRebootPrompt(browser, this);
} else {
prompt_delegate_->OpenSettingsPage(browser);
OnInteractionDone();
}
}
void ChromeCleanerRebootDialogControllerImpl::OnInteractionDone() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
delete this;
}
} // namespace safe_browsing
// 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.
#ifndef CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_REBOOT_DIALOG_CONTROLLER_IMPL_WIN_H_
#define CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_REBOOT_DIALOG_CONTROLLER_IMPL_WIN_H_
#include "base/sequence_checker.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_win.h"
class Browser;
namespace safe_browsing {
class ChromeCleanerRebootDialogControllerImpl
: public ChromeCleanerRebootDialogController {
public:
class PromptDelegate {
public:
virtual ~PromptDelegate();
virtual void ShowChromeCleanerRebootPrompt(
Browser* browser,
ChromeCleanerRebootDialogControllerImpl* controller) = 0;
virtual void OpenSettingsPage(Browser* browser) = 0;
};
// Creates a new controller object and either starts or schedules the reboot
// prompt flow. The new controller object must be created and only accessed
// on the UI thread.
static ChromeCleanerRebootDialogControllerImpl* Create(
ChromeCleanerController* cleaner_controller);
// Same as Create() with a custom delegate.
static ChromeCleanerRebootDialogControllerImpl* Create(
ChromeCleanerController* cleaner_controller,
std::unique_ptr<PromptDelegate> delegate);
// ChromeCleanerRebootDialogController overrides.
void DialogShown() override;
void Accept() override;
void Cancel() override;
void Close() override;
protected:
// Use Create() to create and initialize new objects.
ChromeCleanerRebootDialogControllerImpl(
ChromeCleanerController* cleaner_controller,
std::unique_ptr<PromptDelegate> delegate);
~ChromeCleanerRebootDialogControllerImpl() override;
// Initiate the reboot prompt flow if there is an active browser window.
// Otherwise, registers to start the reboot prompt once a new window becomes
// available.
void MaybeStartRebootPrompt();
// Shows the reboot prompt dialog in |browser| if the reboot prompt experiment
// is on and the Settings page is not the currently active tab. Otherwise,
// this will reopen the Settings page on a background tab.
void StartRebootPromptForBrowser(Browser* browser);
void OnInteractionDone();
ChromeCleanerController* cleaner_controller_ = nullptr;
std::unique_ptr<PromptDelegate> prompt_delegate_;
// Used to check that modifications to |profile_resetters_| are sequenced
// correctly.
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_REBOOT_DIALOG_CONTROLLER_IMPL_WIN_H_
// 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.
#ifndef CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_REBOOT_DIALOG_CONTROLLER_WIN_H_
#define CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_REBOOT_DIALOG_CONTROLLER_WIN_H_
namespace safe_browsing {
// Decides if and when a reboot prompt dialog should be shown. If a dialog is
// shown, provides functions, such as |Accept()| and |Cancel()|, that should
// be called by the Chrome Cleaner Reboot UI in response to user actions.
//
// Implementations manage their own lifetimes and delete themselves once they
// decide that no dialog should be shown or, if the dialog has been shown, once
// the user interacts with it.
class ChromeCleanerRebootDialogController {
public:
// Called by the reboot dialog when the dialog has been shown. Used for
// reporting metrics.
virtual void DialogShown() = 0;
// Called by the reboot dialog when user accepts the reboot prompt. Once
// |Accept()| has been called, the controller will eventually delete itself
// and no member functions should be called after that.
virtual void Accept() = 0;
// Called by the reboot dialog when the dialog is closed via the cancel
// button. Once |Cancel()| has been called, the controller will eventually
// delete itself and no member functions should be called after that.
virtual void Cancel() = 0;
// Called by the reboot dialog when the dialog is closed by some other means
// than the cancel button (for example, by pressing Esc or clicking the 'x' on
// the top of the dialog). After a call to |Close()|, the controller will
// eventually delete itself and no member functions should be called after
// that.
virtual void Close() = 0;
protected:
virtual ~ChromeCleanerRebootDialogController() = default;
};
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_REBOOT_DIALOG_CONTROLLER_WIN_H_
...@@ -185,7 +185,6 @@ ChromeCleanerRunner::LaunchAndWaitForExitOnBackgroundThread() { ...@@ -185,7 +185,6 @@ ChromeCleanerRunner::LaunchAndWaitForExitOnBackgroundThread() {
UMA_HISTOGRAM_SPARSE_SLOWLY( UMA_HISTOGRAM_SPARSE_SLOWLY(
"SoftwareReporter.Cleaner.ExitCodeFromConnectedProcess", exit_code); "SoftwareReporter.Cleaner.ExitCodeFromConnectedProcess", exit_code);
return ProcessStatus(LaunchStatus::kSuccess, exit_code); return ProcessStatus(LaunchStatus::kSuccess, exit_code);
} }
......
// 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/mock_chrome_cleaner_controller_win.h"
namespace safe_browsing {
MockChromeCleanerController::MockChromeCleanerController() = default;
MockChromeCleanerController::~MockChromeCleanerController() = default;
} // namespace safe_browsing
// 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.
#ifndef CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_MOCK_CHROME_CLEANER_CONTROLLER_WIN_H_
#define CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_MOCK_CHROME_CLEANER_CONTROLLER_WIN_H_
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace safe_browsing {
class MockChromeCleanerController
: public safe_browsing::ChromeCleanerController {
public:
MockChromeCleanerController();
~MockChromeCleanerController() override;
MOCK_METHOD0(ShouldShowCleanupInSettingsUI, bool());
MOCK_METHOD0(IsPoweredByPartner, bool());
MOCK_CONST_METHOD0(state, State());
MOCK_CONST_METHOD0(idle_reason, IdleReason());
MOCK_METHOD1(SetLogsEnabled, void(bool));
MOCK_CONST_METHOD0(logs_enabled, bool());
MOCK_METHOD0(ResetIdleState, void());
MOCK_METHOD1(AddObserver, void(Observer*));
MOCK_METHOD1(RemoveObserver, void(Observer*));
MOCK_METHOD1(Scan, void(const safe_browsing::SwReporterInvocation&));
MOCK_METHOD2(ReplyWithUserResponse, void(Profile*, UserResponse));
MOCK_METHOD0(Reboot, void());
};
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_MOCK_CHROME_CLEANER_CONTROLLER_WIN_H_
...@@ -47,6 +47,9 @@ const char kSRTPromptTrial[] = "SRTPromptFieldTrial"; ...@@ -47,6 +47,9 @@ const char kSRTPromptTrial[] = "SRTPromptFieldTrial";
const base::Feature kInBrowserCleanerUIFeature{ const base::Feature kInBrowserCleanerUIFeature{
"InBrowserCleanerUI", base::FEATURE_ENABLED_BY_DEFAULT}; "InBrowserCleanerUI", base::FEATURE_ENABLED_BY_DEFAULT};
extern const base::Feature kRebootPromptDialogFeature{
"RebootPromptDialog", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kCleanerDownloadFeature{"DownloadCleanupToolByBitness", const base::Feature kCleanerDownloadFeature{"DownloadCleanupToolByBitness",
base::FEATURE_DISABLED_BY_DEFAULT}; base::FEATURE_DISABLED_BY_DEFAULT};
...@@ -113,6 +116,14 @@ std::string GetSRTFieldTrialGroupName() { ...@@ -113,6 +116,14 @@ std::string GetSRTFieldTrialGroupName() {
return base::FieldTrialList::FindFullName(kSRTPromptTrial); return base::FieldTrialList::FindFullName(kSRTPromptTrial);
} }
bool IsRebootPromptModal() {
constexpr char kIsModalParam[] = "modal_reboot_prompt";
return base::FeatureList::IsEnabled(kRebootPromptDialogFeature) &&
base::GetFieldTrialParamByFeatureAsBool(kRebootPromptDialogFeature,
kIsModalParam,
/*default_value=*/false);
}
void RecordSRTPromptHistogram(SRTPromptHistogramValue value) { void RecordSRTPromptHistogram(SRTPromptHistogramValue value) {
UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.PromptUsage", value, UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.PromptUsage", value,
SRT_PROMPT_MAX); SRT_PROMPT_MAX);
......
...@@ -56,6 +56,10 @@ enum PromptTypeHistogramValue { ...@@ -56,6 +56,10 @@ enum PromptTypeHistogramValue {
// within Chrome. // within Chrome.
extern const base::Feature kInBrowserCleanerUIFeature; extern const base::Feature kInBrowserCleanerUIFeature;
// When enabled, shows a prompt dialog if a cleanup requires a reboot and the
// Settings page is not the current active tab.
extern const base::Feature kRebootPromptDialogFeature;
extern const char kSRTPromptTrial[]; extern const char kSRTPromptTrial[];
// Returns true if this Chrome is in a field trial group which shows the SRT // Returns true if this Chrome is in a field trial group which shows the SRT
...@@ -79,6 +83,10 @@ std::string GetIncomingSRTSeed(); ...@@ -79,6 +83,10 @@ std::string GetIncomingSRTSeed();
// Returns the group name in the SRTPrompt field trial. // Returns the group name in the SRTPrompt field trial.
std::string GetSRTFieldTrialGroupName(); std::string GetSRTFieldTrialGroupName();
// Returns true if the kRebootPromptDialogFeature is enabled and the prompt
// dialog is modal.
bool IsRebootPromptModal();
// Records a value for the SRT Prompt Histogram. // Records a value for the SRT Prompt Histogram.
void RecordSRTPromptHistogram(SRTPromptHistogramValue value); void RecordSRTPromptHistogram(SRTPromptHistogramValue value);
......
...@@ -2420,6 +2420,8 @@ split_static_library("ui") { ...@@ -2420,6 +2420,8 @@ split_static_library("ui") {
"views/certificate_viewer_win.cc", "views/certificate_viewer_win.cc",
"views/chrome_cleaner_dialog_win.cc", "views/chrome_cleaner_dialog_win.cc",
"views/chrome_cleaner_dialog_win.h", "views/chrome_cleaner_dialog_win.h",
"views/chrome_cleaner_reboot_dialog_win.cc",
"views/chrome_cleaner_reboot_dialog_win.h",
"views/color_chooser_dialog.cc", "views/color_chooser_dialog.cc",
"views/color_chooser_dialog.h", "views/color_chooser_dialog.h",
"views/color_chooser_win.cc", "views/color_chooser_win.cc",
......
...@@ -51,6 +51,7 @@ class PaymentRequestDialog; ...@@ -51,6 +51,7 @@ class PaymentRequestDialog;
namespace safe_browsing { namespace safe_browsing {
class ChromeCleanerController; class ChromeCleanerController;
class ChromeCleanerDialogController; class ChromeCleanerDialogController;
class ChromeCleanerRebootDialogController;
class SettingsResetPromptController; class SettingsResetPromptController;
} }
...@@ -279,6 +280,13 @@ void ShowChromeCleanerPrompt( ...@@ -279,6 +280,13 @@ void ShowChromeCleanerPrompt(
safe_browsing::ChromeCleanerDialogController* dialog_controller, safe_browsing::ChromeCleanerDialogController* dialog_controller,
safe_browsing::ChromeCleanerController* cleaner_controller); safe_browsing::ChromeCleanerController* cleaner_controller);
// Shows the Chrome Cleanup reboot dialog asking the user if they want to
// restart their computer once a cleanup has finished. This is called when the
// Chrome Cleanup ends in a reboot required state.
void ShowChromeCleanerRebootPrompt(
Browser* browser,
safe_browsing::ChromeCleanerRebootDialogController* dialog_controller);
#endif // OS_WIN #endif // OS_WIN
} // namespace chrome } // namespace chrome
......
// 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/ui/views/chrome_cleaner_reboot_dialog_win.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
#include "chrome/browser/ui/test/test_browser_dialog.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace safe_browsing {
namespace {
// Provides tests which allows explicit invocation of the Chrome Cleaner Reboot
// Prompt useful for checking dialog layout or any other interactive
// functionality tests. See docs/testing/test_browser_dialog.md for description
// of the testing framework.
class ChromeCleanerRebootDialog : public DialogBrowserTest {
public:
void SetUpInProcessBrowserTestFixture() override {
scoped_feature_list_.InitAndEnableFeature(kRebootPromptDialogFeature);
}
// DialogBrowserTest overrides.
void ShowDialog(const std::string& name) override {
ON_CALL(mock_cleaner_controller_, state())
.WillByDefault(::testing::Return(
safe_browsing::ChromeCleanerController::State::kRebootRequired));
safe_browsing::ChromeCleanerRebootDialogControllerImpl::Create(
&mock_cleaner_controller_);
}
private:
// Since the DialogBrowserTest can be run interactively, we use NiceMock here
// to suppress warnings about uninteresting calls.
::testing::NiceMock<MockChromeCleanerController> mock_cleaner_controller_;
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(ChromeCleanerRebootDialog, InvokeDialog_default) {
RunDialog();
}
} // namespace
} // namespace safe_browsing
// 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/ui/views/chrome_cleaner_reboot_dialog_win.h"
#include "base/strings/string16.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_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_window.h"
#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_types.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/text_constants.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/widget/widget.h"
namespace chrome {
void ShowChromeCleanerRebootPrompt(
Browser* browser,
safe_browsing::ChromeCleanerRebootDialogController* dialog_controller) {
DCHECK(browser);
DCHECK(dialog_controller);
ChromeCleanerRebootDialog* dialog =
new ChromeCleanerRebootDialog(dialog_controller);
dialog->Show(browser);
}
} // namespace chrome
namespace {
constexpr int kDialogWidth = 448;
constexpr int kDialogHeight = 116;
constexpr int kDialogYOffset = 72;
} // namespace
ChromeCleanerRebootDialog::ChromeCleanerRebootDialog(
safe_browsing::ChromeCleanerRebootDialogController* dialog_controller)
: dialog_controller_(dialog_controller) {
DCHECK(dialog_controller_);
set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
views::TEXT, views::TEXT));
}
ChromeCleanerRebootDialog::~ChromeCleanerRebootDialog() {
// Make sure the controller is correctly notified in case the dialog widget is
// closed by some other means than the dialog buttons.
if (dialog_controller_) {
HandleDialogInteraction(DialogInteractionResult::kClosedOnDestruction);
}
}
void ChromeCleanerRebootDialog::Show(Browser* browser) {
DCHECK(browser);
DCHECK(dialog_controller_);
views::Widget* widget = DialogDelegate::CreateDialogWidget(
this, nullptr, browser->window()->GetNativeWindow());
widget->SetBounds(GetDialogBounds(browser));
widget->Show();
dialog_controller_->DialogShown();
}
// WidgetDelegate overrides.
ui::ModalType ChromeCleanerRebootDialog::GetModalType() const {
return safe_browsing::IsRebootPromptModal() ? ui::MODAL_TYPE_WINDOW
: ui::MODAL_TYPE_NONE;
}
base::string16 ChromeCleanerRebootDialog::GetWindowTitle() const {
DCHECK(dialog_controller_);
return l10n_util::GetStringUTF16(IDS_CHROME_CLEANUP_REBOOT_PROMPT_TITLE);
}
// DialogDelegate overrides.
base::string16 ChromeCleanerRebootDialog::GetDialogButtonLabel(
ui::DialogButton button) const {
DCHECK(button == ui::DIALOG_BUTTON_OK || button == ui::DIALOG_BUTTON_CANCEL);
DCHECK(dialog_controller_);
return button == ui::DIALOG_BUTTON_OK
? l10n_util::GetStringUTF16(
IDS_CHROME_CLEANUP_REBOOT_PROMPT_RESTART_BUTTON_LABEL)
: DialogDelegate::GetDialogButtonLabel(button);
}
bool ChromeCleanerRebootDialog::Accept() {
HandleDialogInteraction(DialogInteractionResult::kAccept);
return true;
}
bool ChromeCleanerRebootDialog::Cancel() {
HandleDialogInteraction(DialogInteractionResult::kCancel);
return true;
}
bool ChromeCleanerRebootDialog::Close() {
HandleDialogInteraction(DialogInteractionResult::kClose);
return true;
}
void ChromeCleanerRebootDialog::HandleDialogInteraction(
DialogInteractionResult result) {
if (!dialog_controller_)
return;
switch (result) {
case DialogInteractionResult::kAccept:
dialog_controller_->Accept();
break;
case DialogInteractionResult::kCancel:
dialog_controller_->Cancel();
break;
case DialogInteractionResult::kClose:
case DialogInteractionResult::kClosedOnDestruction:
// Fallthrough.
dialog_controller_->Close();
break;
}
dialog_controller_ = nullptr;
}
gfx::Rect ChromeCleanerRebootDialog::GetDialogBounds(Browser* browser) const {
gfx::Rect browser_bounds = browser->window()->GetBounds();
return gfx::Rect(
browser_bounds.x() + (browser_bounds.width() - kDialogWidth) / 2,
browser_bounds.y() + kDialogYOffset, kDialogWidth, kDialogHeight);
}
// 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.
#ifndef CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_REBOOT_DIALOG_WIN_H_
#define CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_REBOOT_DIALOG_WIN_H_
#include "base/macros.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/window/dialog_delegate.h"
class Browser;
namespace safe_browsing {
class ChromeCleanerRebootDialogController;
}
// A modal dialog asking the user if they want to restart their computer once
// the Chrome Cleanup tool finished in a reboot required state.
//
// A ChromeCleanerRebootDialogController object will receive information
// about how the user interacts with the dialog. The controller object owns
// itself and will delete itself once it has received information about the
// user's interaction with the dialog.
class ChromeCleanerRebootDialog : public views::DialogDelegateView {
public:
// The |dialog_controller| object manages its own lifetime and is not owned
// by |ChromeCleanerRebootDialog|. See the description of the
// |ChromeCleanerRebootDialogController| class for details.
explicit ChromeCleanerRebootDialog(
safe_browsing::ChromeCleanerRebootDialogController* dialog_controller);
~ChromeCleanerRebootDialog() override;
void Show(Browser* browser);
// views::WidgetDelegate overrides.
ui::ModalType GetModalType() const override;
base::string16 GetWindowTitle() const override;
// views::DialogDelegate overrides.
base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
bool Accept() override;
bool Cancel() override;
bool Close() override;
private:
enum class DialogInteractionResult {
kAccept,
kCancel,
kClose,
kClosedOnDestruction,
};
void HandleDialogInteraction(DialogInteractionResult result);
gfx::Rect GetDialogBounds(Browser* browser) const;
// The pointer will be set to nullptr once the controller has been notified of
// user interaction since the controller can delete itself after that point.
safe_browsing::ChromeCleanerRebootDialogController* dialog_controller_;
DISALLOW_COPY_AND_ASSIGN(ChromeCleanerRebootDialog);
};
#endif // CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_REBOOT_DIALOG_WIN_H_
...@@ -1530,6 +1530,7 @@ test("browser_tests") { ...@@ -1530,6 +1530,7 @@ test("browser_tests") {
"../browser/ui/update_chrome_dialog_browsertest.cc", "../browser/ui/update_chrome_dialog_browsertest.cc",
"../browser/ui/views/apps/app_info_dialog/app_info_dialog_views_browsertest.cc", "../browser/ui/views/apps/app_info_dialog/app_info_dialog_views_browsertest.cc",
"../browser/ui/views/chrome_cleaner_dialog_browsertest_win.cc", "../browser/ui/views/chrome_cleaner_dialog_browsertest_win.cc",
"../browser/ui/views/chrome_cleaner_reboot_dialog_browsertest_win.cc",
"../browser/ui/views/extensions/chooser_dialog_view_browsertest.cc", "../browser/ui/views/extensions/chooser_dialog_view_browsertest.cc",
"../browser/ui/views/hung_renderer_view_browsertest.cc", "../browser/ui/views/hung_renderer_view_browsertest.cc",
"../browser/ui/views/try_chrome_dialog_browsertest.cc", "../browser/ui/views/try_chrome_dialog_browsertest.cc",
...@@ -2007,6 +2008,9 @@ test("browser_tests") { ...@@ -2007,6 +2008,9 @@ test("browser_tests") {
"../browser/extensions/webstore_startup_installer_browsertest.cc", "../browser/extensions/webstore_startup_installer_browsertest.cc",
"../browser/extensions/window_open_apitest.cc", "../browser/extensions/window_open_apitest.cc",
"../browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc", "../browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc",
"../browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc",
"../browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.cc",
"../browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h",
"../browser/safe_browsing/chrome_cleaner/settings_resetter_browsertest_win.cc", "../browser/safe_browsing/chrome_cleaner/settings_resetter_browsertest_win.cc",
"../browser/safe_browsing/settings_reset_prompt/default_settings_fetcher_browsertest.cc", "../browser/safe_browsing/settings_reset_prompt/default_settings_fetcher_browsertest.cc",
"../browser/safe_browsing/settings_reset_prompt/settings_reset_dependency_browsertest_win.cc", "../browser/safe_browsing/settings_reset_prompt/settings_reset_dependency_browsertest_win.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment