blob: 5e62b4d2164cb549c18a3edda87fdfca9fdd5973 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_H_
#define CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_H_
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/wall_clock_timer.h"
#include "chrome/browser/safe_browsing/application_advanced_protection_status_detector.h"
#include "chrome/browser/upgrade_detector/upgrade_detector.h"
#include "chrome/browser/upgrade_detector/upgrade_observer.h"
#include "components/prefs/pref_change_registrar.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h"
#else
#include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_desktop.h"
#endif // BUILDFLAG(IS_CHROMEOS)
namespace base {
class Clock;
class TickClock;
} // namespace base
// A class that observes changes to the browser.relaunch_notification
// preference (which is backed by the RelaunchNotification policy
// setting) and upgrade notifications from the UpgradeDetector. The two
// values for the RelaunchNotification policy setting are handled as follows:
//
// On Chrome desktop:
// - Recommended (1): The controller displays the relaunch recommended bubble on
// each change to the UpgradeDetector's upgrade_notification_stage (an
// "annoyance level" of low, elevated, grace or high). Once the high annoyance
// level is reached, the controller continually reshows a the bubble on a
// timer with a period equal to the time delta between the "elevated" and
// "high" showings.
//
// - Required (2): The controller displays the relaunch required dialog when the
// UpgradeDetector's upgrade_notification_stage changes to an "annoyance level"
// of low, elevated, and grace. The browser is relaunched when the "annoyance
// level" reaches "high".
//
// On Chrome OS both notifications (recommended and required, described above)
// are shown in the unified system tray, overwriting the default "update
// available" notification. It cannot be deferred, so it persists until reboot.
// In certain conditions, the preference value could be overridden by the
// UpgradeDetector which then takes priority over the original value and any
// further changes to the preference have no effect.
class RelaunchNotificationController
: public UpgradeObserver,
public safe_browsing::ApplicationAdvancedProtectionStatusDetector::
StatusObserver {
public:
// |upgrade_detector| is expected to be the process-wide detector, and must
// outlive the controller.
explicit RelaunchNotificationController(UpgradeDetector* upgrade_detector);
RelaunchNotificationController(const RelaunchNotificationController&) =
delete;
RelaunchNotificationController& operator=(
const RelaunchNotificationController&) = delete;
~RelaunchNotificationController() override;
protected:
// The length of the final countdown given to the user before the browser is
// summarily relaunched on Chrome desktop, or the device is rebooted on
// Chrome OS.
static constexpr base::TimeDelta kRelaunchGracePeriod = base::Hours(1);
RelaunchNotificationController(UpgradeDetector* upgrade_detector,
const base::Clock* 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:
void OnUpgradeRecommended() override;
void OnRelaunchOverriddenToRequired(bool overridden) override;
// ApplicationAdvancedProtectionStatusDetector::StatusObserver:
void OnApplicationAdvancedProtectionStatusChanged(bool enabled) override;
private:
enum class NotificationStyle {
kNone, // No notifications are shown.
kRecommended, // Relaunches are recommended.
kRequired, // Relaunches are required.
};
// Adjusts to the current notification style as indicated by the
// browser.relaunch_notification Local State preference. If the notification
// style has been overridden, then that value is given priority over the
// preference value.
void HandleCurrentStyle();
// Bring the instance out of or back to dormant mode.
void StartObservingUpgrades();
void StopObservingUpgrades();
// Observe BrowserAdvanceProtectionStatus.
void StartObservingAPStatus();
// Shows the proper notification based on the preference setting and starts
// the timer to either reshow the bubble or restart the browser/device as
// appropriate. |level| is the current annoyance level reported by the
// UpgradeDetector, and |high_deadline| is the time at which the
// UpgradeDetector will reach the high annoyance level; see the class comment
// for further details.
void ShowRelaunchNotification(
UpgradeDetector::UpgradeNotificationAnnoyanceLevel level,
base::Time high_deadline);
// Closes any previously-shown notifications. This is safe to call if no
// notifications have been shown. Notifications may be closed by other means
// (e.g., by the user), so there is no expectation that a previously-shown
// notification is still open when this is invoked. The timer to either
// repeatedly show the relaunch recommended notification or to force a
// relaunch once the deadline is reached is also stopped.
void CloseRelaunchNotification();
// Starts or reschedules a timer to periodically re-show the relaunch
// recommended bubble.
void StartReshowTimer();
// Run on a timer once high annoyance has been reached to re-show the relaunch
// recommended bubble.
void OnReshowRelaunchRecommended();
// Handles a new |level| and/or |high_deadline| by adjusting the runtime of
// the relaunch timer, updating the deadline displayed in the title of the
// relaunch required notification (if shown), and showing it if needed.
void HandleRelaunchRequiredState(
UpgradeDetector::UpgradeNotificationAnnoyanceLevel level,
base::Time high_deadline);
// Update |last_relaunch_notification_time_| before calling
// DoNotifyRelaunchRecommended. |past_deadline| reflects whether the
// Recommended deadline was already passed or not.
void NotifyRelaunchRecommended(bool past_deadline);
// Calls DoNotifyRelaunchRequired to show the notification.
void NotifyRelaunchRequired();
// The following methods, which are invoked by the controller to show or close
// notifications, are virtual for the sake of testing.
// Shows the relaunch recommended notification if it is not already open.
// |past_deadline| reflects whether the Recommended deadline was already
// passed or not.
virtual void DoNotifyRelaunchRecommended(bool past_deadline);
// Shows the relaunch required notification if it is not already open.
// |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.
// If |is_notification_style_ap_required|, the relaunch notification is shown
// with Advanced Protection string and icon.
virtual void DoNotifyRelaunchRequired(
bool is_notification_style_ap_required,
base::Time relaunch_deadline,
base::OnceCallback<base::Time()> on_visible);
// Closes bubble or dialog if either is still open on desktop, or sets the
// default notification on Chrome OS.
virtual void Close();
// Run to restart the browser/device once the relaunch deadline is reached
// when relaunches are required by policy.
virtual void OnRelaunchDeadlineExpired();
// The process-wide upgrade detector.
const raw_ptr<UpgradeDetector> upgrade_detector_;
// A provider of Time to the controller and its timer for the sake of
// testability.
const raw_ptr<const base::Clock> clock_;
// The platform-specific implementation.
RelaunchNotificationControllerPlatformImpl platform_impl_;
// Observes changes to the browser.relaunch_notification Local State pref.
PrefChangeRegistrar pref_change_registrar_;
// The last observed notification style. When kNone, the controller is
// said to be "dormant" as there is no work for it to do aside from watch for
// changes to browser.relaunch_notification. When any other value, the
// controller is observing the UpgradeDetector to detect when to show a
// notification.
NotificationStyle last_notification_style_;
// The last observed annoyance level. This member is unconditionally
// UPGRADE_ANNOYANCE_NONE when the controller is dormant
// (browser.relaunch_notification is 0).
UpgradeDetector::UpgradeNotificationAnnoyanceLevel last_level_;
// The last observed high annoyance deadline.
base::Time last_high_deadline_;
// The last time recommended relaunch notification triggered
base::Time last_relaunch_notification_time_;
// A timer used either to repeatedly reshow the relaunch recommended bubble
// once the high annoyance level has been reached, or to trigger browser
// relaunch once the relaunch required dialog's deadline is reached.
base::WallClockTimer timer_;
// A flag to denote that the relaunch notification type policy value has been
// overridden to required. Changes to the policy value will not affect the
// notification type.
bool notification_type_required_overridden_ = false;
// A flag to denote that relaunch notification should be required for Advanced
// Protection Program. This is true when there is at least a profile with
// Advanced Protection and relaunch notification is not already required by
// other override or the enterprise policy.
bool notification_style_overridden_for_advanced_protection_ = false;
// Observes changes to application Advanced Protection status.
base::ScopedObservation<
safe_browsing::ApplicationAdvancedProtectionStatusDetector,
safe_browsing::ApplicationAdvancedProtectionStatusDetector::
StatusObserver>
advanced_protection_observation_{this};
};
#endif // CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_RELAUNCH_NOTIFICATION_CONTROLLER_H_