1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/upgrade_detector.h"
8 #include "base/command_line.h"
9 #include "base/time/tick_clock.h"
10 #include "chrome/app/vector_icons/vector_icons.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/lifetime/application_lifetime.h"
13 #include "chrome/browser/ui/browser_otr_state.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/pref_names.h"
16 #include "components/prefs/pref_registry_simple.h"
17 #include "components/prefs/pref_service.h"
18 #include "ui/gfx/color_palette.h"
19 #include "ui/gfx/paint_vector_icon.h"
21 // How long to wait between checks for whether the user has been idle.
22 static const int kIdleRepeatingTimerWait = 10; // Minutes (seconds if testing).
24 // How much idle time (since last input even was detected) must have passed
25 // until we notify that a critical update has occurred.
26 static const int kIdleAmount = 2; // Hours (or seconds, if testing).
28 bool UseTestingIntervals() {
29 // If a command line parameter specifying how long the upgrade check should
30 // be, we assume it is for testing and switch to using seconds instead of
32 const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
33 return !cmd_line.GetSwitchValueASCII(
34 switches::kCheckForUpdateIntervalSec).empty();
38 void UpgradeDetector::RegisterPrefs(PrefRegistrySimple* registry) {
39 registry->RegisterBooleanPref(prefs::kAttemptedToEnableAutoupdate, false);
42 gfx::Image UpgradeDetector::GetIcon() {
43 SkColor color = gfx::kPlaceholderColor;
44 switch (upgrade_notification_stage_) {
45 case UPGRADE_ANNOYANCE_NONE:
47 case UPGRADE_ANNOYANCE_LOW:
48 color = gfx::kGoogleGreen700;
50 case UPGRADE_ANNOYANCE_ELEVATED:
51 color = gfx::kGoogleYellow700;
53 case UPGRADE_ANNOYANCE_HIGH:
54 case UPGRADE_ANNOYANCE_CRITICAL:
55 color = gfx::kGoogleRed700;
58 DCHECK_NE(gfx::kPlaceholderColor, color);
60 return gfx::Image(gfx::CreateVectorIcon(kBrowserToolsUpdateIcon, color));
63 UpgradeDetector::UpgradeDetector(const base::TickClock* tick_clock)
64 : tick_clock_(tick_clock),
65 upgrade_available_(UPGRADE_AVAILABLE_NONE),
66 best_effort_experiment_updates_available_(false),
67 critical_experiment_updates_available_(false),
68 critical_update_acknowledged_(false),
69 is_factory_reset_required_(false),
70 idle_check_timer_(tick_clock_),
71 upgrade_notification_stage_(UPGRADE_ANNOYANCE_NONE),
72 notify_upgrade_(false) {
73 // Not all tests provide a PrefService for local_state().
74 PrefService* local_state = g_browser_process->local_state();
76 pref_change_registrar_.Init(local_state);
77 // base::Unretained is safe here because |this| outlives the registrar.
78 pref_change_registrar_.Add(
79 prefs::kRelaunchNotificationPeriod,
81 &UpgradeDetector::OnRelaunchNotificationPeriodPrefChanged,
82 base::Unretained(this)));
86 UpgradeDetector::~UpgradeDetector() {
89 void UpgradeDetector::NotifyOutdatedInstall() {
90 for (auto& observer : observer_list_)
91 observer.OnOutdatedInstall();
94 void UpgradeDetector::NotifyOutdatedInstallNoAutoUpdate() {
95 for (auto& observer : observer_list_)
96 observer.OnOutdatedInstallNoAutoUpdate();
100 base::TimeDelta UpgradeDetector::GetRelaunchNotificationPeriod() {
101 // Not all tests provide a PrefService for local_state().
102 auto* local_state = g_browser_process->local_state();
104 return base::TimeDelta();
105 const auto* preference =
106 local_state->FindPreference(prefs::kRelaunchNotificationPeriod);
107 const int value = preference->GetValue()->GetInt();
108 // Enforce the preference's documented minimum value.
109 static constexpr base::TimeDelta kMinValue = base::TimeDelta::FromHours(1);
110 if (preference->IsDefaultValue() || value < kMinValue.InMilliseconds())
111 return base::TimeDelta();
112 return base::TimeDelta::FromMilliseconds(value);
115 void UpgradeDetector::NotifyUpgrade() {
116 // An implementation will request that a notification be sent after dropping
117 // back to the "none" annoyance level if the RelaunchNotificationPeriod
118 // setting changes to a large enough value such that none of the revised
119 // thresholds have been hit. In this case, consumers should not perceive that
120 // an upgrade is available when checking notify_upgrade(). In practice, this
121 // is only the case on desktop Chrome and not Chrome OS, where the lowest
122 // threshold is hit the moment the upgrade is detected.
123 notify_upgrade_ = upgrade_notification_stage_ != UPGRADE_ANNOYANCE_NONE;
125 NotifyUpgradeRecommended();
126 if (upgrade_available_ == UPGRADE_NEEDED_OUTDATED_INSTALL) {
127 NotifyOutdatedInstall();
128 } else if (upgrade_available_ == UPGRADE_NEEDED_OUTDATED_INSTALL_NO_AU) {
129 NotifyOutdatedInstallNoAutoUpdate();
130 } else if (upgrade_available_ == UPGRADE_AVAILABLE_CRITICAL ||
131 critical_experiment_updates_available_) {
132 TriggerCriticalUpdate();
136 void UpgradeDetector::NotifyUpgradeRecommended() {
137 for (auto& observer : observer_list_)
138 observer.OnUpgradeRecommended();
141 void UpgradeDetector::NotifyCriticalUpgradeInstalled() {
142 for (auto& observer : observer_list_)
143 observer.OnCriticalUpgradeInstalled();
146 void UpgradeDetector::NotifyUpdateOverCellularAvailable() {
147 for (auto& observer : observer_list_)
148 observer.OnUpdateOverCellularAvailable();
151 void UpgradeDetector::NotifyUpdateOverCellularOneTimePermissionGranted() {
152 for (auto& observer : observer_list_)
153 observer.OnUpdateOverCellularOneTimePermissionGranted();
156 void UpgradeDetector::TriggerCriticalUpdate() {
157 const base::TimeDelta idle_timer = UseTestingIntervals() ?
158 base::TimeDelta::FromSeconds(kIdleRepeatingTimerWait) :
159 base::TimeDelta::FromMinutes(kIdleRepeatingTimerWait);
160 idle_check_timer_.Start(FROM_HERE, idle_timer, this,
161 &UpgradeDetector::CheckIdle);
164 void UpgradeDetector::CheckIdle() {
165 // CalculateIdleState expects an interval in seconds.
166 int idle_time_allowed = UseTestingIntervals() ? kIdleAmount :
167 kIdleAmount * 60 * 60;
170 idle_time_allowed, base::Bind(&UpgradeDetector::IdleCallback,
171 base::Unretained(this)));
174 void UpgradeDetector::IdleCallback(ui::IdleState state) {
175 // Don't proceed while an incognito window is open. The timer will still
176 // keep firing, so this function will get a chance to re-evaluate this.
177 if (chrome::IsIncognitoSessionActive())
181 case ui::IDLE_STATE_LOCKED:
182 // Computer is locked, auto-restart.
183 idle_check_timer_.Stop();
184 chrome::AttemptRestart();
186 case ui::IDLE_STATE_IDLE:
187 // Computer has been idle for long enough, show warning.
188 idle_check_timer_.Stop();
189 NotifyCriticalUpgradeInstalled();
191 case ui::IDLE_STATE_ACTIVE:
192 case ui::IDLE_STATE_UNKNOWN:
195 NOTREACHED(); // Need to add any new value above (either providing
196 // automatic restart or show notification to user).
201 void UpgradeDetector::AddObserver(UpgradeObserver* observer) {
202 observer_list_.AddObserver(observer);
205 void UpgradeDetector::RemoveObserver(UpgradeObserver* observer) {
206 observer_list_.RemoveObserver(observer);