Commit 3864f083 authored by Aya ElAttar's avatar Aya ElAttar Committed by Commit Bot

Increase the relaunch deadline if the user has potentially seen the

notification and the relaunch deadline is in less than the grace period.

Bug: 1044716
Change-Id: I299bb6a62029826b40a7fb739f332bd868bf75c6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2041600
Commit-Queue: Aya Elsayed <ayaelattar@google.com>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarGreg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#743502}
parent 348175b0
specific_include_rules = {
"relaunch_notification_controller_platform_impl_chromeos\.cc": [
"+ash/shell.h",
],
"relaunch_notification_controller_unittest\.cc": [
"+ash/shell.h",
"+ash/test/ash_test_helper.h"
],
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h" #include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h"
#include <algorithm> #include <algorithm>
#include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
...@@ -231,8 +232,8 @@ void RelaunchNotificationController::HandleRelaunchRequiredState( ...@@ -231,8 +232,8 @@ void RelaunchNotificationController::HandleRelaunchRequiredState(
DCHECK_EQ(last_notification_style_, NotificationStyle::kRequired); DCHECK_EQ(last_notification_style_, NotificationStyle::kRequired);
// Make no changes if the new deadline is not in the future and the browser is // Make no changes if the new deadline is not in the future and the browser is
// within the grace period of the previous deadline. The user has already been // within the grace period of the previous deadline. The user has already seen
// given the fifteen-minutes countdown so just let it go. // the one-hour countdown so just let it go.
const base::Time now = clock_->Now(); const base::Time now = clock_->Now();
if (timer_.IsRunning()) { if (timer_.IsRunning()) {
const base::Time& desired_run_time = timer_.desired_run_time(); const base::Time& desired_run_time = timer_.desired_run_time();
...@@ -241,7 +242,7 @@ void RelaunchNotificationController::HandleRelaunchRequiredState( ...@@ -241,7 +242,7 @@ void RelaunchNotificationController::HandleRelaunchRequiredState(
return; return;
} }
// Compute the new deadline (minimally fifteen minutes into the future). // Compute the new deadline (minimally one hour into the future).
const base::Time deadline = const base::Time deadline =
std::max(high_deadline, now) + kRelaunchGracePeriod; std::max(high_deadline, now) + kRelaunchGracePeriod;
...@@ -250,7 +251,6 @@ void RelaunchNotificationController::HandleRelaunchRequiredState( ...@@ -250,7 +251,6 @@ void RelaunchNotificationController::HandleRelaunchRequiredState(
&RelaunchNotificationController::OnRelaunchDeadlineExpired); &RelaunchNotificationController::OnRelaunchDeadlineExpired);
if (platform_impl_.IsRequiredNotificationShown()) { if (platform_impl_.IsRequiredNotificationShown()) {
// Tell the notification to update its title if it is showing.
platform_impl_.SetDeadline(deadline); platform_impl_.SetDeadline(deadline);
} else { } else {
// Otherwise, show the dialog if there has been a level change or if the // Otherwise, show the dialog if there has been a level change or if the
...@@ -259,6 +259,22 @@ void RelaunchNotificationController::HandleRelaunchRequiredState( ...@@ -259,6 +259,22 @@ void RelaunchNotificationController::HandleRelaunchRequiredState(
NotifyRelaunchRequired(); NotifyRelaunchRequired();
} }
} }
base::Time RelaunchNotificationController::IncreaseRelaunchDeadlineOnShow() {
DCHECK(timer_.IsRunning());
DCHECK(!timer_.desired_run_time().is_null());
base::Time relaunch_deadline = timer_.desired_run_time();
// Push the dealdine back if needed so that the user has at least the grace
// period to decide what to do.
relaunch_deadline =
std::max(clock_->Now() + kRelaunchGracePeriod, relaunch_deadline);
timer_.Start(FROM_HERE, relaunch_deadline, this,
&RelaunchNotificationController::OnRelaunchDeadlineExpired);
return relaunch_deadline;
}
void RelaunchNotificationController::StartReshowTimer() { void RelaunchNotificationController::StartReshowTimer() {
DCHECK_EQ(last_notification_style_, NotificationStyle::kRecommended); DCHECK_EQ(last_notification_style_, NotificationStyle::kRecommended);
DCHECK(!last_relaunch_notification_time_.is_null()); DCHECK(!last_relaunch_notification_time_.is_null());
...@@ -292,18 +308,28 @@ void RelaunchNotificationController::DoNotifyRelaunchRecommended( ...@@ -292,18 +308,28 @@ void RelaunchNotificationController::DoNotifyRelaunchRecommended(
void RelaunchNotificationController::NotifyRelaunchRequired() { void RelaunchNotificationController::NotifyRelaunchRequired() {
DCHECK(timer_.IsRunning()); DCHECK(timer_.IsRunning());
DCHECK(!timer_.desired_run_time().is_null()); DCHECK(!timer_.desired_run_time().is_null());
DoNotifyRelaunchRequired(timer_.desired_run_time()); DoNotifyRelaunchRequired(
timer_.desired_run_time(),
base::BindOnce(
&RelaunchNotificationController::IncreaseRelaunchDeadlineOnShow,
base::Unretained(this)));
} }
void RelaunchNotificationController::DoNotifyRelaunchRequired( void RelaunchNotificationController::DoNotifyRelaunchRequired(
base::Time deadline) { base::Time relaunch_deadline,
platform_impl_.NotifyRelaunchRequired(deadline); base::OnceCallback<base::Time()> on_visible) {
platform_impl_.NotifyRelaunchRequired(relaunch_deadline,
std::move(on_visible));
} }
void RelaunchNotificationController::Close() { void RelaunchNotificationController::Close() {
platform_impl_.CloseRelaunchNotification(); platform_impl_.CloseRelaunchNotification();
} }
void RelaunchNotificationController::SetDeadline(base::Time deadline) {
platform_impl_.SetDeadline(deadline);
}
void RelaunchNotificationController::OnRelaunchDeadlineExpired() { void RelaunchNotificationController::OnRelaunchDeadlineExpired() {
chrome::RelaunchIgnoreUnloadHandlers(); chrome::RelaunchIgnoreUnloadHandlers();
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_H_ #ifndef CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_H_
#define CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_H_ #define CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_H_
#include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/ui/views/relaunch_notification/wall_clock_timer.h" #include "chrome/browser/ui/views/relaunch_notification/wall_clock_timer.h"
...@@ -38,7 +39,7 @@ class TickClock; ...@@ -38,7 +39,7 @@ class TickClock;
// //
// - Required (2): The controller displays the relaunch required dialog on each // - Required (2): The controller displays the relaunch required dialog on each
// change to the UpgradeDetector's upgrade_notification_stage (described // change to the UpgradeDetector's upgrade_notification_stage (described
// above). The browser is relaunched fifteen minutes after the third and final // above). The browser is relaunched one hour after the third and final
// showing of the dialog (which takes place when the UpgradeDetector reaches // showing of the dialog (which takes place when the UpgradeDetector reaches
// the high annoyance level). // the high annoyance level).
// //
...@@ -57,12 +58,16 @@ class RelaunchNotificationController : public UpgradeObserver { ...@@ -57,12 +58,16 @@ class RelaunchNotificationController : public UpgradeObserver {
// summarily relaunched on Chrome desktop, or the device is rebooted on // summarily relaunched on Chrome desktop, or the device is rebooted on
// Chrome OS. // Chrome OS.
static constexpr base::TimeDelta kRelaunchGracePeriod = static constexpr base::TimeDelta kRelaunchGracePeriod =
base::TimeDelta::FromMinutes(60); base::TimeDelta::FromHours(1);
RelaunchNotificationController(UpgradeDetector* upgrade_detector, RelaunchNotificationController(UpgradeDetector* upgrade_detector,
const base::Clock* clock, const base::Clock* clock,
const base::TickClock* tick_clock); const base::TickClock* tick_clock);
// The deadline may be extended to ensure that the user has at least the full
// duration of the grace period to take action.
base::Time IncreaseRelaunchDeadlineOnShow();
// UpgradeObserver: // UpgradeObserver:
void OnUpgradeRecommended() override; void OnUpgradeRecommended() override;
...@@ -122,8 +127,8 @@ class RelaunchNotificationController : public UpgradeObserver { ...@@ -122,8 +127,8 @@ class RelaunchNotificationController : public UpgradeObserver {
// Recommended deadline was already passed or not. // Recommended deadline was already passed or not.
void NotifyRelaunchRecommended(bool past_deadline); void NotifyRelaunchRecommended(bool past_deadline);
// Provide deadline to DoNotifyRelaunchRequired. // Calls DoNotifyRelaunchRequired to show the notification.
virtual void NotifyRelaunchRequired(); void NotifyRelaunchRequired();
// The following methods, which are invoked by the controller to show or close // The following methods, which are invoked by the controller to show or close
// notifications, are virtual for the sake of testing. // notifications, are virtual for the sake of testing.
...@@ -134,12 +139,20 @@ class RelaunchNotificationController : public UpgradeObserver { ...@@ -134,12 +139,20 @@ class RelaunchNotificationController : public UpgradeObserver {
virtual void DoNotifyRelaunchRecommended(bool past_deadline); virtual void DoNotifyRelaunchRecommended(bool past_deadline);
// Shows the relaunch required notification if it is not already open. // Shows the relaunch required notification if it is not already open.
virtual void DoNotifyRelaunchRequired(base::Time deadline); // |on_visible| is a callback to be run when the notification is potentially
// seen by the user to push back the relaunch deadline if the remaining time
// is less than the grace period.
virtual void DoNotifyRelaunchRequired(
base::Time relaunch_deadline,
base::OnceCallback<base::Time()> on_visible);
// Closes bubble or dialog if either is still open on desktop, or sets the // Closes bubble or dialog if either is still open on desktop, or sets the
// default notification on Chrome OS. // default notification on Chrome OS.
virtual void Close(); virtual void Close();
// Updates the required relaunch deadline in the UX.
virtual void SetDeadline(base::Time deadline);
// Run to restart the browser/device once the relaunch deadline is reached // Run to restart the browser/device once the relaunch deadline is reached
// when relaunches are required by policy. // when relaunches are required by policy.
virtual void OnRelaunchDeadlineExpired(); virtual void OnRelaunchDeadlineExpired();
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h" #include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h"
#include "ash/public/cpp/update_types.h" #include "ash/public/cpp/update_types.h"
#include "ash/shell.h"
#include "base/bind.h" #include "base/bind.h"
#include "chrome/browser/ui/ash/system_tray_client.h" #include "chrome/browser/ui/ash/system_tray_client.h"
#include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_metrics.h" #include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_metrics.h"
...@@ -35,7 +36,8 @@ void RelaunchNotificationControllerPlatformImpl::RecordRecommendedShowResult() { ...@@ -35,7 +36,8 @@ void RelaunchNotificationControllerPlatformImpl::RecordRecommendedShowResult() {
} }
void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRequired( void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRequired(
base::Time deadline) { base::Time deadline,
base::OnceCallback<base::Time()> on_visible) {
if (!relaunch_required_timer_) { if (!relaunch_required_timer_) {
relaunch_required_timer_ = std::make_unique<RelaunchRequiredTimer>( relaunch_required_timer_ = std::make_unique<RelaunchRequiredTimer>(
deadline, deadline,
...@@ -48,6 +50,13 @@ void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRequired( ...@@ -48,6 +50,13 @@ void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRequired(
} }
RefreshRelaunchRequiredTitle(); RefreshRelaunchRequiredTitle();
if (!CanScheduleReboot()) {
on_visible_ = std::move(on_visible);
StartObserving();
} else {
StopObserving();
}
} }
void RelaunchNotificationControllerPlatformImpl::CloseRelaunchNotification() { void RelaunchNotificationControllerPlatformImpl::CloseRelaunchNotification() {
...@@ -55,11 +64,14 @@ void RelaunchNotificationControllerPlatformImpl::CloseRelaunchNotification() { ...@@ -55,11 +64,14 @@ void RelaunchNotificationControllerPlatformImpl::CloseRelaunchNotification() {
ash::NotificationStyle::kDefault, base::string16(), base::string16()); ash::NotificationStyle::kDefault, base::string16(), base::string16());
recorded_shown_ = false; recorded_shown_ = false;
relaunch_required_timer_.reset(); relaunch_required_timer_.reset();
on_visible_.Reset();
StopObserving();
} }
void RelaunchNotificationControllerPlatformImpl::SetDeadline( void RelaunchNotificationControllerPlatformImpl::SetDeadline(
base::Time deadline) { base::Time deadline) {
relaunch_required_timer_->SetDeadline(deadline); if (relaunch_required_timer_)
relaunch_required_timer_->SetDeadline(deadline);
} }
void RelaunchNotificationControllerPlatformImpl:: void RelaunchNotificationControllerPlatformImpl::
...@@ -77,15 +89,53 @@ void RelaunchNotificationControllerPlatformImpl:: ...@@ -77,15 +89,53 @@ void RelaunchNotificationControllerPlatformImpl::
} }
} }
bool RelaunchNotificationControllerPlatformImpl::IsRequiredNotificationShown()
const {
return relaunch_required_timer_ != nullptr;
}
void RelaunchNotificationControllerPlatformImpl:: void RelaunchNotificationControllerPlatformImpl::
RefreshRelaunchRequiredTitle() { RefreshRelaunchRequiredTitle() {
SystemTrayClient::Get()->SetUpdateNotificationState( // SystemTrayClient may not exist in unit tests.
ash::NotificationStyle::kAdminRequired, if (SystemTrayClient::Get()) {
relaunch_required_timer_->GetWindowTitle(), SystemTrayClient::Get()->SetUpdateNotificationState(
l10n_util::GetStringUTF16(IDS_RELAUNCH_REQUIRED_BODY)); ash::NotificationStyle::kAdminRequired,
relaunch_required_timer_->GetWindowTitle(),
l10n_util::GetStringUTF16(IDS_RELAUNCH_REQUIRED_BODY));
}
} }
bool RelaunchNotificationControllerPlatformImpl::IsRequiredNotificationShown() void RelaunchNotificationControllerPlatformImpl::OnPowerStateChanged(
const { chromeos::DisplayPowerState power_state) {
return relaunch_required_timer_ != nullptr; if (CanScheduleReboot() && on_visible_) {
base::Time new_deadline = std::move(on_visible_).Run();
SetDeadline(new_deadline);
StopObserving();
}
}
void RelaunchNotificationControllerPlatformImpl::OnSessionStateChanged() {
if (CanScheduleReboot() && on_visible_) {
base::Time new_deadline = std::move(on_visible_).Run();
SetDeadline(new_deadline);
StopObserving();
}
}
bool RelaunchNotificationControllerPlatformImpl::CanScheduleReboot() {
return ash::Shell::Get()->display_configurator()->IsDisplayOn() &&
session_manager::SessionManager::Get()->session_state() ==
session_manager::SessionState::ACTIVE;
}
void RelaunchNotificationControllerPlatformImpl::StartObserving() {
if (!display_observer_.IsObservingSources())
display_observer_.Add(ash::Shell::Get()->display_configurator());
if (!session_observer_.IsObservingSources())
session_observer_.Add(session_manager::SessionManager::Get());
}
void RelaunchNotificationControllerPlatformImpl::StopObserving() {
display_observer_.RemoveAll();
session_observer_.RemoveAll();
} }
...@@ -7,21 +7,29 @@ ...@@ -7,21 +7,29 @@
#include <memory> #include <memory>
#include "base/callback.h"
#include "base/scoped_observer.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/session_manager/core/session_manager.h"
#include "components/session_manager/core/session_manager_observer.h"
#include "ui/display/manager/display_configurator.h"
class RelaunchRequiredTimer; class RelaunchRequiredTimer;
class RelaunchNotificationControllerPlatformImpl { class RelaunchNotificationControllerPlatformImpl
: public display::DisplayConfigurator::Observer,
public session_manager::SessionManagerObserver {
public: public:
RelaunchNotificationControllerPlatformImpl(); RelaunchNotificationControllerPlatformImpl();
~RelaunchNotificationControllerPlatformImpl(); ~RelaunchNotificationControllerPlatformImpl() override;
// Shows the relaunch recommended notification if it is not already open. // Shows the relaunch recommended notification if it is not already open.
void NotifyRelaunchRecommended(base::Time detection_time, bool past_deadline); void NotifyRelaunchRecommended(base::Time detection_time, bool past_deadline);
// Shows the relaunch required notification if it is not already open. // Shows the relaunch required notification if it is not already open.
void NotifyRelaunchRequired(base::Time deadline); void NotifyRelaunchRequired(base::Time deadline,
base::OnceCallback<base::Time()> on_visible);
// Sets the notification title to the default one on Chrome OS. // Sets the notification title to the default one on Chrome OS.
void CloseRelaunchNotification(); void CloseRelaunchNotification();
...@@ -33,6 +41,12 @@ class RelaunchNotificationControllerPlatformImpl { ...@@ -33,6 +41,12 @@ class RelaunchNotificationControllerPlatformImpl {
// Returns true if relaunch required notification is shown. // Returns true if relaunch required notification is shown.
bool IsRequiredNotificationShown() const; bool IsRequiredNotificationShown() const;
// display::DisplayConfigurator::Observer overrides.
void OnPowerStateChanged(chromeos::DisplayPowerState power_state) override;
// session_manager::SessionManagerObserver overrides.
void OnSessionStateChanged() override;
private: private:
// Callback triggered whenever the recommended notification's title has to // Callback triggered whenever the recommended notification's title has to
// refresh. // refresh.
...@@ -45,6 +59,15 @@ class RelaunchNotificationControllerPlatformImpl { ...@@ -45,6 +59,15 @@ class RelaunchNotificationControllerPlatformImpl {
// refresh. // refresh.
void RefreshRelaunchRequiredTitle(); void RefreshRelaunchRequiredTitle();
// Returns true if the display is on && the session is active
bool CanScheduleReboot();
// Registers itself to observe display & session state changes
void StartObserving();
// Removes itself from observe display & session state observers
void StopObserving();
// Timer that takes care of the string refresh in the relaunch required // Timer that takes care of the string refresh in the relaunch required
// notification title. // notification title.
std::unique_ptr<RelaunchRequiredTimer> relaunch_required_timer_; std::unique_ptr<RelaunchRequiredTimer> relaunch_required_timer_;
...@@ -52,6 +75,15 @@ class RelaunchNotificationControllerPlatformImpl { ...@@ -52,6 +75,15 @@ class RelaunchNotificationControllerPlatformImpl {
// Indicate that show of the Recommended notification was already recorded. // Indicate that show of the Recommended notification was already recorded.
bool recorded_shown_ = false; bool recorded_shown_ = false;
base::OnceCallback<base::Time()> on_visible_;
ScopedObserver<display::DisplayConfigurator,
display::DisplayConfigurator::Observer>
display_observer_{this};
ScopedObserver<session_manager::SessionManager,
session_manager::SessionManagerObserver>
session_observer_{this};
DISALLOW_COPY_AND_ASSIGN(RelaunchNotificationControllerPlatformImpl); DISALLOW_COPY_AND_ASSIGN(RelaunchNotificationControllerPlatformImpl);
}; };
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/lifetime/application_lifetime.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_list.h" #include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_metrics.h" #include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_metrics.h"
#include "chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.h" #include "chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.h"
...@@ -51,6 +52,13 @@ Browser* FindLastActiveTabbedBrowser() { ...@@ -51,6 +52,13 @@ Browser* FindLastActiveTabbedBrowser() {
RelaunchNotificationControllerPlatformImpl:: RelaunchNotificationControllerPlatformImpl::
RelaunchNotificationControllerPlatformImpl() = default; RelaunchNotificationControllerPlatformImpl() = default;
RelaunchNotificationControllerPlatformImpl::
~RelaunchNotificationControllerPlatformImpl() {
DCHECK(!widget_);
if (on_visible_)
BrowserList::RemoveObserver(this);
}
void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRecommended( void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRecommended(
base::Time detection_time, base::Time detection_time,
bool /*past_deadline*/) { bool /*past_deadline*/) {
...@@ -74,35 +82,58 @@ void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRecommended( ...@@ -74,35 +82,58 @@ void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRecommended(
} }
void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRequired( void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRequired(
base::Time deadline) { base::Time deadline,
base::OnceCallback<base::Time()> on_visible) {
// Nothing to do if the dialog is visible. // Nothing to do if the dialog is visible.
if (widget_) if (widget_)
return; return;
// Show the dialog in the most recently active browser. // Show the dialog in the active tabbed browser window.
Browser* browser = FindLastActiveTabbedBrowser(); Browser* browser = chrome::FindBrowserWithActiveWindow();
relaunch_notification::RecordRequiredShowResult( if (browser && browser->is_type_normal()) {
browser ? relaunch_notification::ShowResult::kShown DCHECK(!on_visible_);
: GetNotShownReason()); ShowRequiredNotification(browser, deadline);
if (!browser) relaunch_notification::RecordRequiredShowResult(
relaunch_notification::ShowResult::kShown);
return; return;
}
widget_ = RelaunchRequiredDialogView::Show( relaunch_notification::RecordRequiredShowResult(GetNotShownReason());
browser, deadline, base::BindRepeating(&chrome::AttemptRelaunch));
// Monitor the widget so that |widget_| can be cleared on close. // If the instance is not already waiting for one to become active from a
widget_->AddObserver(this); // previous call, start observing now.
if (!on_visible_)
BrowserList::AddObserver(this);
// Hold on to the callback until an active tabbed browser is found.
on_visible_ = std::move(on_visible);
last_relaunch_deadline_ = deadline;
} }
void RelaunchNotificationControllerPlatformImpl::CloseRelaunchNotification() { void RelaunchNotificationControllerPlatformImpl::CloseRelaunchNotification() {
if (widget_) if (widget_)
widget_->Close(); widget_->Close();
if (on_visible_) {
BrowserList::RemoveObserver(this);
on_visible_.Reset();
last_relaunch_deadline_ = base::Time();
}
has_shown_ = false;
} }
void RelaunchNotificationControllerPlatformImpl::SetDeadline( void RelaunchNotificationControllerPlatformImpl::SetDeadline(
base::Time deadline) { base::Time deadline) {
DCHECK(widget_); // Nothing to do if the dialog hasn't been shown yet (because no tabbed
RelaunchRequiredDialogView::FromWidget(widget_)->SetDeadline(deadline); // browser has become active) or if the user has seen and dismissed the
// dialog.
if (widget_)
RelaunchRequiredDialogView::FromWidget(widget_)->SetDeadline(deadline);
// Hold on to the new deadline if the instance is waiting for a Browser to
// become active.
if (on_visible_)
last_relaunch_deadline_ = deadline;
} }
bool RelaunchNotificationControllerPlatformImpl::IsRequiredNotificationShown() bool RelaunchNotificationControllerPlatformImpl::IsRequiredNotificationShown()
...@@ -116,3 +147,39 @@ void RelaunchNotificationControllerPlatformImpl::OnWidgetClosing( ...@@ -116,3 +147,39 @@ void RelaunchNotificationControllerPlatformImpl::OnWidgetClosing(
widget->RemoveObserver(this); widget->RemoveObserver(this);
widget_ = nullptr; widget_ = nullptr;
} }
void RelaunchNotificationControllerPlatformImpl::OnWidgetDestroying(
views::Widget* widget) {
DCHECK_EQ(widget, widget_);
widget->RemoveObserver(this);
widget_ = nullptr;
}
void RelaunchNotificationControllerPlatformImpl::OnBrowserSetLastActive(
Browser* browser) {
// Ignore non-tabbed browsers.
if (!browser->is_type_normal())
return;
BrowserList::RemoveObserver(this);
base::Time new_deadline =
has_shown_ ? last_relaunch_deadline_ : std::move(on_visible_).Run();
DCHECK(!new_deadline.is_null());
on_visible_.Reset();
last_relaunch_deadline_ = base::Time();
ShowRequiredNotification(browser, new_deadline);
}
void RelaunchNotificationControllerPlatformImpl::ShowRequiredNotification(
Browser* browser,
base::Time deadline) {
widget_ = RelaunchRequiredDialogView::Show(
browser, deadline, base::BindRepeating(&chrome::AttemptRelaunch));
has_shown_ = true;
// Monitor the widget so that |widget_| can be cleared on close/destruction.
widget_->AddObserver(this);
}
...@@ -5,24 +5,30 @@ ...@@ -5,24 +5,30 @@
#ifndef CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_PLATFORM_IMPL_DESKTOP_H_ #ifndef CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_PLATFORM_IMPL_DESKTOP_H_
#define CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_PLATFORM_IMPL_DESKTOP_H_ #define CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_PLATFORM_IMPL_DESKTOP_H_
#include "base/callback.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "ui/views/widget/widget_observer.h" #include "ui/views/widget/widget_observer.h"
namespace views { namespace views {
class Widget; class Widget;
} }
class RelaunchNotificationControllerPlatformImpl class RelaunchNotificationControllerPlatformImpl : public views::WidgetObserver,
: public views::WidgetObserver { public BrowserListObserver {
public: public:
RelaunchNotificationControllerPlatformImpl(); RelaunchNotificationControllerPlatformImpl();
~RelaunchNotificationControllerPlatformImpl() override;
// Shows the relaunch recommended notification if it is not already open. // Shows the relaunch recommended notification if it is not already open.
void NotifyRelaunchRecommended(base::Time detection_time, bool past_deadline); void NotifyRelaunchRecommended(base::Time detection_time, bool past_deadline);
// Shows the relaunch required notification if it is not already open. // Shows the relaunch required notification in the most recently active
void NotifyRelaunchRequired(base::Time deadline); // browser. window if it is not already open. |on_visible| is run when the
// notification is potentially seen to push the deadline back if the remaining
// time is less than the grace period.
void NotifyRelaunchRequired(base::Time deadline,
base::OnceCallback<base::Time()> on_visible);
// Closes the bubble or dialog if either is still open. // Closes the bubble or dialog if either is still open.
void CloseRelaunchNotification(); void CloseRelaunchNotification();
...@@ -37,12 +43,31 @@ class RelaunchNotificationControllerPlatformImpl ...@@ -37,12 +43,31 @@ class RelaunchNotificationControllerPlatformImpl
protected: protected:
// views::WidgetObserver: // views::WidgetObserver:
void OnWidgetClosing(views::Widget* widget) override; void OnWidgetClosing(views::Widget* widget) override;
void OnWidgetDestroying(views::Widget* widget) override;
// BrowserListObserver:
void OnBrowserSetLastActive(Browser* browser) override;
private: private:
// Shows the notification in |browser| for a relaunch that will take place
// at |deadline|.
void ShowRequiredNotification(Browser* browser, base::Time deadline);
// The widget hosting the bubble or dialog, or nullptr if neither is is // The widget hosting the bubble or dialog, or nullptr if neither is is
// currently shown. // currently shown.
views::Widget* widget_ = nullptr; views::Widget* widget_ = nullptr;
// A callback run when the relaunch required notification first becomes
// visible to the user. This callback is valid only while the instance is
// waiting for a tabbed browser to become active.
base::OnceCallback<base::Time()> on_visible_;
// A boolean to record if the relaunch notification has been shown or not.
bool has_shown_ = false;
// The last relaunch deadline if the relaunch notification has_shown_.
base::Time last_relaunch_deadline_;
DISALLOW_COPY_AND_ASSIGN(RelaunchNotificationControllerPlatformImpl); DISALLOW_COPY_AND_ASSIGN(RelaunchNotificationControllerPlatformImpl);
}; };
......
...@@ -9,8 +9,10 @@ ...@@ -9,8 +9,10 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/optional.h"
#include "base/power_monitor/power_monitor.h" #include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_source.h" #include "base/power_monitor/power_monitor_source.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/time/clock.h" #include "base/time/clock.h"
#include "base/time/tick_clock.h" #include "base/time/tick_clock.h"
...@@ -23,6 +25,26 @@ ...@@ -23,6 +25,26 @@
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_CHROMEOS)
#include "ash/shell.h"
#include "ash/test/ash_test_helper.h"
#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "ui/display/manager/display_configurator.h"
#include "ui/display/manager/test/action_logger.h"
#include "ui/display/manager/test/test_native_display_delegate.h"
#else
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
#endif // defined(OS_CHROMEOS)
using ::testing::_;
using ::testing::Eq;
using ::testing::ResultOf;
using ::testing::Return;
namespace { namespace {
// A delegate interface for handling the actions taken by the controller. // A delegate interface for handling the actions taken by the controller.
...@@ -32,6 +54,7 @@ class ControllerDelegate { ...@@ -32,6 +54,7 @@ class ControllerDelegate {
virtual void NotifyRelaunchRecommended() = 0; virtual void NotifyRelaunchRecommended() = 0;
virtual void NotifyRelaunchRequired() = 0; virtual void NotifyRelaunchRequired() = 0;
virtual void Close() = 0; virtual void Close() = 0;
virtual void SetDeadline(base::Time deadline) = 0;
virtual void OnRelaunchDeadlineExpired() = 0; virtual void OnRelaunchDeadlineExpired() = 0;
protected: protected:
...@@ -51,17 +74,27 @@ class FakeRelaunchNotificationController ...@@ -51,17 +74,27 @@ class FakeRelaunchNotificationController
using RelaunchNotificationController::kRelaunchGracePeriod; using RelaunchNotificationController::kRelaunchGracePeriod;
base::Time IncreaseRelaunchDeadlineOnShow() {
return RelaunchNotificationController::IncreaseRelaunchDeadlineOnShow();
}
private: private:
void DoNotifyRelaunchRecommended(bool /*past_deadline*/) override { void DoNotifyRelaunchRecommended(bool /*past_deadline*/) override {
delegate_->NotifyRelaunchRecommended(); delegate_->NotifyRelaunchRecommended();
} }
void DoNotifyRelaunchRequired(base::Time deadline) override { void DoNotifyRelaunchRequired(
base::Time deadline,
base::OnceCallback<base::Time()> on_visible) override {
delegate_->NotifyRelaunchRequired(); delegate_->NotifyRelaunchRequired();
} }
void Close() override { delegate_->Close(); } void Close() override { delegate_->Close(); }
void SetDeadline(base::Time deadline) override {
delegate_->SetDeadline(deadline);
}
void OnRelaunchDeadlineExpired() override { void OnRelaunchDeadlineExpired() override {
delegate_->OnRelaunchDeadlineExpired(); delegate_->OnRelaunchDeadlineExpired();
} }
...@@ -77,6 +110,7 @@ class MockControllerDelegate : public ControllerDelegate { ...@@ -77,6 +110,7 @@ class MockControllerDelegate : public ControllerDelegate {
MOCK_METHOD0(NotifyRelaunchRecommended, void()); MOCK_METHOD0(NotifyRelaunchRecommended, void());
MOCK_METHOD0(NotifyRelaunchRequired, void()); MOCK_METHOD0(NotifyRelaunchRequired, void());
MOCK_METHOD0(Close, void()); MOCK_METHOD0(Close, void());
MOCK_METHOD1(SetDeadline, void(base::Time));
MOCK_METHOD0(OnRelaunchDeadlineExpired, void()); MOCK_METHOD0(OnRelaunchDeadlineExpired, void());
}; };
...@@ -237,27 +271,27 @@ TEST_F(RelaunchNotificationControllerTest, RecommendedByPolicy) { ...@@ -237,27 +271,27 @@ TEST_F(RelaunchNotificationControllerTest, RecommendedByPolicy) {
// Nothing shown if the level is broadcast at NONE or VERY_LOW. // Nothing shown if the level is broadcast at NONE or VERY_LOW.
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_NONE); UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Show for each level change, but not for repeat notifications. // Show for each level change, but not for repeat notifications.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// First move time to the high annoyance deadline. // First move time to the high annoyance deadline.
base::Time high_annoyance_deadline = base::Time high_annoyance_deadline =
...@@ -267,47 +301,47 @@ TEST_F(RelaunchNotificationControllerTest, RecommendedByPolicy) { ...@@ -267,47 +301,47 @@ TEST_F(RelaunchNotificationControllerTest, RecommendedByPolicy) {
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_HIGH); UpgradeDetector::UPGRADE_ANNOYANCE_HIGH);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// The timer should be running to reshow at the detector's delta. // The timer should be running to reshow at the detector's delta.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta()); FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta()); FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Drop back to elevated to stop the reshows and ensure there are none. // Drop back to elevated to stop the reshows and ensure there are none.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta()); FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// And closed if the level drops back to very low. // And closed if the level drops back to very low.
EXPECT_CALL(mock_controller_delegate, Close()); EXPECT_CALL(mock_controller_delegate, Close());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Back up to elevated brings the bubble back. // Back up to elevated brings the bubble back.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// And it is closed if the level drops back to none. // And it is closed if the level drops back to none.
EXPECT_CALL(mock_controller_delegate, Close()); EXPECT_CALL(mock_controller_delegate, Close());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_NONE); UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_NONE); UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// With the browser.relaunch_notification preference set to 2, the controller // With the browser.relaunch_notification preference set to 2, the controller
...@@ -324,49 +358,49 @@ TEST_F(RelaunchNotificationControllerTest, RequiredByPolicy) { ...@@ -324,49 +358,49 @@ TEST_F(RelaunchNotificationControllerTest, RequiredByPolicy) {
// Nothing shown if the level is broadcast at NONE. // Nothing shown if the level is broadcast at NONE.
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_NONE); UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Show for each level change, but not for repeat notifications. // Show for each change to a higher level, but not for repeat notifications.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_HIGH); UpgradeDetector::UPGRADE_ANNOYANCE_HIGH);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_HIGH); UpgradeDetector::UPGRADE_ANNOYANCE_HIGH);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// And closed if the level drops back to none. // And closed if the level drops back to none.
EXPECT_CALL(mock_controller_delegate, Close()); EXPECT_CALL(mock_controller_delegate, Close());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_NONE); UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_NONE); UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// Flipping the policy should have no effect when at level NONE or VERY_LOW. // Flipping the policy should have no effect when at level NONE or VERY_LOW.
...@@ -378,32 +412,32 @@ TEST_F(RelaunchNotificationControllerTest, PolicyChangesNoUpgrade) { ...@@ -378,32 +412,32 @@ TEST_F(RelaunchNotificationControllerTest, PolicyChangesNoUpgrade) {
&mock_controller_delegate); &mock_controller_delegate);
SetNotificationPref(1); SetNotificationPref(1);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(2); SetNotificationPref(2);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(3); // Bogus value! SetNotificationPref(3); // Bogus value!
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(0); SetNotificationPref(0);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(1); SetNotificationPref(1);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(2); SetNotificationPref(2);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(3); // Bogus value! SetNotificationPref(3); // Bogus value!
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(0); SetNotificationPref(0);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// Policy changes at an elevated level should show the appropriate notification. // Policy changes at an elevated level should show the appropriate notification.
...@@ -416,20 +450,20 @@ TEST_F(RelaunchNotificationControllerTest, PolicyChangesWithUpgrade) { ...@@ -416,20 +450,20 @@ TEST_F(RelaunchNotificationControllerTest, PolicyChangesWithUpgrade) {
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
SetNotificationPref(1); SetNotificationPref(1);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, Close()); EXPECT_CALL(mock_controller_delegate, Close());
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
SetNotificationPref(2); SetNotificationPref(2);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, Close()); EXPECT_CALL(mock_controller_delegate, Close());
SetNotificationPref(0); SetNotificationPref(0);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// Relaunch is forced when the deadline is reached. // Relaunch is forced when the deadline is reached.
...@@ -443,15 +477,16 @@ TEST_F(RelaunchNotificationControllerTest, RequiredDeadlineReached) { ...@@ -443,15 +477,16 @@ TEST_F(RelaunchNotificationControllerTest, RequiredDeadlineReached) {
// As in the RequiredByPolicy test, the dialog should be shown. // As in the RequiredByPolicy test, the dialog should be shown.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// And the relaunch should be forced after the deadline passes. // And the relaunch should be forced after the deadline passes.
EXPECT_CALL(mock_controller_delegate, OnRelaunchDeadlineExpired()); EXPECT_CALL(mock_controller_delegate, OnRelaunchDeadlineExpired());
FastForwardBy(fake_upgrade_detector().high_threshold() + FastForwardBy(fake_upgrade_detector().high_threshold() +
FakeRelaunchNotificationController::kRelaunchGracePeriod); FakeRelaunchNotificationController::kRelaunchGracePeriod);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// No forced relaunch if the dialog is closed. // No forced relaunch if the dialog is closed.
...@@ -465,19 +500,20 @@ TEST_F(RelaunchNotificationControllerTest, RequiredDeadlineReachedNoPolicy) { ...@@ -465,19 +500,20 @@ TEST_F(RelaunchNotificationControllerTest, RequiredDeadlineReachedNoPolicy) {
// As in the RequiredByPolicy test, the dialog should be shown. // As in the RequiredByPolicy test, the dialog should be shown.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// And then closed if the policy is cleared. // And then closed if the policy is cleared.
EXPECT_CALL(mock_controller_delegate, Close()); EXPECT_CALL(mock_controller_delegate, Close());
SetNotificationPref(0); SetNotificationPref(0);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// And no relaunch should take place. // And no relaunch should take place.
FastForwardBy(fake_upgrade_detector().high_threshold() + FastForwardBy(fake_upgrade_detector().high_threshold() +
FakeRelaunchNotificationController::kRelaunchGracePeriod); FakeRelaunchNotificationController::kRelaunchGracePeriod);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// NotificationPeriod changes should do nothing at any policy setting when the // NotificationPeriod changes should do nothing at any policy setting when the
...@@ -493,19 +529,19 @@ TEST_F(RelaunchNotificationControllerTest, NonePeriodChange) { ...@@ -493,19 +529,19 @@ TEST_F(RelaunchNotificationControllerTest, NonePeriodChange) {
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
base::TimeDelta::FromDays(1)); base::TimeDelta::FromDays(1));
FastForwardBy(fake_upgrade_detector().high_threshold()); FastForwardBy(fake_upgrade_detector().high_threshold());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(1); SetNotificationPref(1);
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
base::TimeDelta::FromHours(23)); base::TimeDelta::FromHours(23));
FastForwardBy(fake_upgrade_detector().high_threshold()); FastForwardBy(fake_upgrade_detector().high_threshold());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(2); SetNotificationPref(2);
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
base::TimeDelta::FromHours(22)); base::TimeDelta::FromHours(22));
FastForwardBy(fake_upgrade_detector().high_threshold()); FastForwardBy(fake_upgrade_detector().high_threshold());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// NotificationPeriod changes should do nothing at any policy setting when the // NotificationPeriod changes should do nothing at any policy setting when the
...@@ -519,25 +555,25 @@ TEST_F(RelaunchNotificationControllerTest, VeryLowPeriodChange) { ...@@ -519,25 +555,25 @@ TEST_F(RelaunchNotificationControllerTest, VeryLowPeriodChange) {
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Reduce the period. // Reduce the period.
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
base::TimeDelta::FromDays(1)); base::TimeDelta::FromDays(1));
FastForwardBy(fake_upgrade_detector().high_threshold()); FastForwardBy(fake_upgrade_detector().high_threshold());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(1); SetNotificationPref(1);
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
base::TimeDelta::FromHours(23)); base::TimeDelta::FromHours(23));
FastForwardBy(fake_upgrade_detector().high_threshold()); FastForwardBy(fake_upgrade_detector().high_threshold());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(2); SetNotificationPref(2);
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
base::TimeDelta::FromHours(22)); base::TimeDelta::FromHours(22));
FastForwardBy(fake_upgrade_detector().high_threshold()); FastForwardBy(fake_upgrade_detector().high_threshold());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// NotificationPeriod changes impact reshows of the relaunch recommended bubble. // NotificationPeriod changes impact reshows of the relaunch recommended bubble.
...@@ -558,57 +594,57 @@ TEST_F(RelaunchNotificationControllerTest, PeriodChangeRecommended) { ...@@ -558,57 +594,57 @@ TEST_F(RelaunchNotificationControllerTest, PeriodChangeRecommended) {
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_HIGH); UpgradeDetector::UPGRADE_ANNOYANCE_HIGH);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Advance time partway to the reshow, but not all the way there. // Advance time partway to the reshow, but not all the way there.
FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta() * 0.9); FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta() * 0.9);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Now shorten the period dramatically and expect an immediate reshow. // Now shorten the period dramatically and expect an immediate reshow.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
fake_upgrade_detector().high_threshold() / 10); fake_upgrade_detector().high_threshold() / 10);
RunUntilIdle(); RunUntilIdle();
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// And expect another reshow at the new delta. // And expect another reshow at the new delta.
base::TimeDelta short_reshow_delta = base::TimeDelta short_reshow_delta =
upgrade_detector()->GetHighAnnoyanceLevelDelta(); upgrade_detector()->GetHighAnnoyanceLevelDelta();
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
FastForwardBy(short_reshow_delta); FastForwardBy(short_reshow_delta);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Now lengthen the period and expect no immediate reshow. // Now lengthen the period and expect no immediate reshow.
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
fake_upgrade_detector().high_threshold() * 10); fake_upgrade_detector().high_threshold() * 10);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Move forward by the short delta to be sure there's no reshow there. // Move forward by the short delta to be sure there's no reshow there.
FastForwardBy(short_reshow_delta); FastForwardBy(short_reshow_delta);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Move forward the rest of the way to the new delta and expect a reshow. // Move forward the rest of the way to the new delta and expect a reshow.
base::TimeDelta long_reshow_delta = base::TimeDelta long_reshow_delta =
upgrade_detector()->GetHighAnnoyanceLevelDelta(); upgrade_detector()->GetHighAnnoyanceLevelDelta();
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
FastForwardBy(long_reshow_delta - short_reshow_delta); FastForwardBy(long_reshow_delta - short_reshow_delta);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Similar to the above, move time forward a little bit. // Similar to the above, move time forward a little bit.
FastForwardBy(long_reshow_delta * 0.1); FastForwardBy(long_reshow_delta * 0.1);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Shorten the period a bit, but not enough to force a reshow. // Shorten the period a bit, but not enough to force a reshow.
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
fake_upgrade_detector().high_threshold() * 0.9); fake_upgrade_detector().high_threshold() * 0.9);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// And ensure that moving forward the rest of the way to the new delta causes // And ensure that moving forward the rest of the way to the new delta causes
// a reshow. // a reshow.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRecommended());
FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta() - FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta() -
long_reshow_delta * 0.1); long_reshow_delta * 0.1);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// NotificationPeriod changes impact reshows of the relaunch required dialog. // NotificationPeriod changes impact reshows of the relaunch required dialog.
...@@ -620,49 +656,316 @@ TEST_F(RelaunchNotificationControllerTest, PeriodChangeRequired) { ...@@ -620,49 +656,316 @@ TEST_F(RelaunchNotificationControllerTest, PeriodChangeRequired) {
upgrade_detector(), GetMockClock(), GetMockTickClock(), upgrade_detector(), GetMockClock(), GetMockTickClock(),
&mock_controller_delegate); &mock_controller_delegate);
// Get up to low annoyance so that the relaunch timer is running.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW); UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Move forward partway to the current deadline. Nothing should happen. // Move forward partway to the current deadline. Nothing should happen.
base::Time high_annoyance_deadline = base::Time high_annoyance_deadline =
upgrade_detector()->GetHighAnnoyanceDeadline(); upgrade_detector()->GetHighAnnoyanceDeadline();
FastForwardBy((high_annoyance_deadline - GetMockClock()->Now()) / 2); FastForwardBy((high_annoyance_deadline - GetMockClock()->Now()) / 2);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Lengthen the period, thereby pushing out the deadline. // Lengthen the period, thereby pushing out the deadline.
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
fake_upgrade_detector().high_threshold() * 2); fake_upgrade_detector().high_threshold() * 2);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Ensure that nothing happens when the old deadline passes. // Ensure that nothing happens when the old deadline passes.
FastForwardBy(high_annoyance_deadline + FastForwardBy(high_annoyance_deadline +
FakeRelaunchNotificationController::kRelaunchGracePeriod - FakeRelaunchNotificationController::kRelaunchGracePeriod -
GetMockClock()->Now()); GetMockClock()->Now());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// But now we enter elevated annoyance level and show the dialog. // But now we enter elevated annoyance level and show the dialog.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange( fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED); UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Jumping to the new deadline relaunches the browser. // Jumping to the new deadline relaunches the browser.
EXPECT_CALL(mock_controller_delegate, OnRelaunchDeadlineExpired()); EXPECT_CALL(mock_controller_delegate, OnRelaunchDeadlineExpired());
FastForwardBy(upgrade_detector()->GetHighAnnoyanceDeadline() + FastForwardBy(upgrade_detector()->GetHighAnnoyanceDeadline() +
FakeRelaunchNotificationController::kRelaunchGracePeriod - FakeRelaunchNotificationController::kRelaunchGracePeriod -
GetMockClock()->Now()); GetMockClock()->Now());
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Shorten the period, bringing in the deadline. Expect the dialog to show and // Shorten the period, bringing in the deadline. Expect the dialog to show and
// a relaunch after the grace period passes. // a relaunch after the grace period passes.
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired()); EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastHighThresholdChange( fake_upgrade_detector().BroadcastHighThresholdChange(
fake_upgrade_detector().high_threshold() / 2); fake_upgrade_detector().high_threshold() / 2);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, OnRelaunchDeadlineExpired());
FastForwardBy(FakeRelaunchNotificationController::kRelaunchGracePeriod);
::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
}
// Test that that the deadline is extended by the grace period when the
// notification is potentially seen
TEST_F(RelaunchNotificationControllerTest, DeferredRequired) {
SetNotificationPref(2);
::testing::StrictMock<MockControllerDelegate> mock_controller_delegate;
FakeRelaunchNotificationController controller(
upgrade_detector(), GetMockClock(), GetMockTickClock(),
&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
// Move time just before the original deadline.
FastForwardBy(fake_upgrade_detector().high_threshold() +
0.5 * FakeRelaunchNotificationController::kRelaunchGracePeriod);
// Suddenly, the UX becomes available.
base::Time deadline = controller.IncreaseRelaunchDeadlineOnShow();
ASSERT_EQ(deadline,
GetMockClock()->Now() +
FakeRelaunchNotificationController::kRelaunchGracePeriod);
// And the relaunch is extended by the grace period.
EXPECT_CALL(mock_controller_delegate, OnRelaunchDeadlineExpired()); EXPECT_CALL(mock_controller_delegate, OnRelaunchDeadlineExpired());
FastForwardBy(FakeRelaunchNotificationController::kRelaunchGracePeriod); FastForwardBy(FakeRelaunchNotificationController::kRelaunchGracePeriod);
::testing::Mock::VerifyAndClear(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
}
#if defined(OS_CHROMEOS)
class RelaunchNotificationControllerPlatformImplTest : public ::testing::Test {
protected:
RelaunchNotificationControllerPlatformImplTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
~RelaunchNotificationControllerPlatformImplTest() override {
ash_test_helper_.TearDown();
}
void SetUp() override {
ash::AshTestHelper::InitParams init_params;
init_params.start_session = false;
ash_test_helper_.SetUp(init_params);
user_manager_ = new chromeos::FakeChromeUserManager();
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
base::WrapUnique(user_manager_));
const char test_user_email[] = "test_user@example.com";
const AccountId test_account_id(AccountId::FromUserEmail(test_user_email));
user_manager_->AddUser(test_account_id);
user_manager_->LoginUser(test_account_id);
session_manager_.CreateSession(test_account_id, test_user_email, false);
session_manager_.SetSessionState(session_manager::SessionState::ACTIVE);
logger_ = std::make_unique<display::test::ActionLogger>();
native_display_delegate_ =
new display::test::TestNativeDisplayDelegate(logger_.get());
ash::Shell::Get()->display_configurator()->SetDelegateForTesting(
std::unique_ptr<display::NativeDisplayDelegate>(
native_display_delegate_));
}
void LockScreen() {
session_manager_.SetSessionState(session_manager::SessionState::LOCKED);
}
void UnLockScreen() {
session_manager_.SetSessionState(session_manager::SessionState::ACTIVE);
}
void TurnDisplayOff() {
ash::Shell::Get()->display_configurator()->SetDisplayPower(
chromeos::DISPLAY_POWER_ALL_OFF, 0, base::DoNothing());
}
void TurnDisplayOn() {
ash::Shell::Get()->display_configurator()->SetDisplayPower(
chromeos::DISPLAY_POWER_ALL_ON, 0, base::DoNothing());
}
RelaunchNotificationControllerPlatformImpl& platform_impl() { return impl_; }
// Returns the TaskEnvironment's MockClock.
const base::Clock* GetMockClock() { return task_environment_.GetMockClock(); }
private:
content::BrowserTaskEnvironment task_environment_;
RelaunchNotificationControllerPlatformImpl impl_;
ash::AshTestHelper ash_test_helper_;
session_manager::SessionManager session_manager_;
chromeos::FakeChromeUserManager* user_manager_;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
std::unique_ptr<display::test::ActionLogger> logger_;
display::NativeDisplayDelegate* native_display_delegate_;
};
// SynchronousNotification
TEST_F(RelaunchNotificationControllerPlatformImplTest,
SynchronousNotification) {
UnLockScreen();
TurnDisplayOn();
// Expect the platform_impl to query for the deadline synchronously.
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
}
// Deferred Notification when the display is off then on.
TEST_F(RelaunchNotificationControllerPlatformImplTest,
DeferredNotificationDisplayOff) {
TurnDisplayOff();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_CALL(callback, Run());
TurnDisplayOn();
::testing::Mock::VerifyAndClearExpectations(&callback);
}
// Deferred Notification when the display is off then on.
TEST_F(RelaunchNotificationControllerPlatformImplTest,
DeferredNotificationSessionLocked) {
LockScreen();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_CALL(callback, Run());
UnLockScreen();
::testing::Mock::VerifyAndClearExpectations(&callback);
}
// Multiple screen on & off.
TEST_F(RelaunchNotificationControllerPlatformImplTest,
RequiredDeadlineReachedAfterMultipleResume) {
TurnDisplayOff();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_CALL(callback, Run());
TurnDisplayOn();
TurnDisplayOff();
TurnDisplayOn();
TurnDisplayOff();
TurnDisplayOn();
::testing::Mock::VerifyAndClearExpectations(&callback);
}
// Multiple session locks & unlocks.
TEST_F(RelaunchNotificationControllerPlatformImplTest,
RequiredDeadlineReachedBeforeMultipleUnlock) {
LockScreen();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_CALL(callback, Run());
UnLockScreen();
LockScreen();
UnLockScreen();
LockScreen();
UnLockScreen();
::testing::Mock::VerifyAndClearExpectations(&callback);
}
#else // (!OS_CHROMEOS)
class RelaunchNotificationControllerPlatformImplTest
: public TestWithBrowserView {
protected:
RelaunchNotificationControllerPlatformImplTest() : TestWithBrowserView() {}
void SetUp() override {
TestWithBrowserView::SetUp();
impl_.emplace();
}
void SetVisibility(bool is_visible) {
if (is_visible)
browser_view()->Show();
else
browser_view()->Hide();
// Allow UI tasks to run so that the browser becomes fully active/inactive.
task_environment()->RunUntilIdle();
}
RelaunchNotificationControllerPlatformImpl& platform_impl() { return *impl_; }
private:
base::Optional<RelaunchNotificationControllerPlatformImpl> impl_;
};
TEST_F(RelaunchNotificationControllerPlatformImplTest,
SynchronousNotification) {
// Make the UX visible to the user so that no delay will be incurred
ASSERT_NO_FATAL_FAILURE(SetVisibility(true));
// Expect the platform_impl to show the notification synchronously.
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
base::Time deadline =
base::Time::FromDeltaSinceWindowsEpoch(base::TimeDelta::FromHours(1));
// There should be no query at the time of showing.
platform_impl().NotifyRelaunchRequired(deadline, callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
ASSERT_NO_FATAL_FAILURE(SetVisibility(false));
// There should be no query because the browser isn't visible.
platform_impl().NotifyRelaunchRequired(deadline, callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
// There should be no query because this isn't the first time to show the
// notification.
ASSERT_NO_FATAL_FAILURE(SetVisibility(true));
::testing::Mock::VerifyAndClearExpectations(&callback);
} }
TEST_F(RelaunchNotificationControllerPlatformImplTest, DeferredDeadline) {
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
base::Time deadline =
base::Time::FromDeltaSinceWindowsEpoch(base::TimeDelta::FromHours(1));
// There should be no query because the browser isn't visible.
platform_impl().NotifyRelaunchRequired(deadline, callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
// The query should happen once the notification is potentially seen.
EXPECT_CALL(callback, Run()).WillOnce(Return(deadline));
ASSERT_NO_FATAL_FAILURE(SetVisibility(true));
::testing::Mock::VerifyAndClearExpectations(&callback);
ASSERT_NO_FATAL_FAILURE(SetVisibility(false));
// There should be no query because the browser isn't visible.
platform_impl().NotifyRelaunchRequired(deadline, callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
// There should be no query because this isn't the first time to show the
// notification.
ASSERT_NO_FATAL_FAILURE(SetVisibility(true));
::testing::Mock::VerifyAndClearExpectations(&callback);
}
#endif
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