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.
4
5#include "chrome/browser/upgrade_detector.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/prefs/pref_registry_simple.h"
10#include "chrome/browser/chrome_notification_types.h"
11#include "chrome/browser/lifetime/application_lifetime.h"
12#include "chrome/browser/ui/browser_otr_state.h"
13#include "chrome/common/chrome_switches.h"
14#include "chrome/common/pref_names.h"
15#include "content/public/browser/notification_service.h"
16#include "grit/theme_resources.h"
17
18// How long to wait between checks for whether the user has been idle.
19static const int kIdleRepeatingTimerWait = 10;  // Minutes (seconds if testing).
20
21// How much idle time (since last input even was detected) must have passed
22// until we notify that a critical update has occurred.
23static const int kIdleAmount = 2;  // Hours (or seconds, if testing).
24
25bool UseTestingIntervals() {
26  // If a command line parameter specifying how long the upgrade check should
27  // be, we assume it is for testing and switch to using seconds instead of
28  // hours.
29  const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
30  return !cmd_line.GetSwitchValueASCII(
31      switches::kCheckForUpdateIntervalSec).empty();
32}
33
34// static
35void UpgradeDetector::RegisterPrefs(PrefRegistrySimple* registry) {
36  registry->RegisterBooleanPref(prefs::kRestartLastSessionOnShutdown, false);
37  registry->RegisterBooleanPref(prefs::kWasRestarted, false);
38  registry->RegisterBooleanPref(prefs::kAttemptedToEnableAutoupdate, false);
39}
40
41int UpgradeDetector::GetIconResourceID() {
42  switch (upgrade_notification_stage_) {
43    case UPGRADE_ANNOYANCE_NONE:
44      return 0;
45    case UPGRADE_ANNOYANCE_LOW:
46      return IDR_UPDATE_MENU_SEVERITY_LOW;
47    case UPGRADE_ANNOYANCE_ELEVATED:
48      return IDR_UPDATE_MENU_SEVERITY_MEDIUM;
49    case UPGRADE_ANNOYANCE_HIGH:
50      return IDR_UPDATE_MENU_SEVERITY_HIGH;
51    case UPGRADE_ANNOYANCE_SEVERE:
52      return IDR_UPDATE_MENU_SEVERITY_HIGH;
53    case UPGRADE_ANNOYANCE_CRITICAL:
54      return IDR_UPDATE_MENU_SEVERITY_HIGH;
55  }
56  NOTREACHED();
57  return 0;
58}
59
60UpgradeDetector::UpgradeDetector()
61    : upgrade_available_(UPGRADE_AVAILABLE_NONE),
62      best_effort_experiment_updates_available_(false),
63      critical_experiment_updates_available_(false),
64      critical_update_acknowledged_(false),
65      upgrade_notification_stage_(UPGRADE_ANNOYANCE_NONE),
66      notify_upgrade_(false) {
67}
68
69UpgradeDetector::~UpgradeDetector() {
70}
71
72void UpgradeDetector::NotifyUpgradeRecommended() {
73  notify_upgrade_ = true;
74
75  TriggerNotification(chrome::NOTIFICATION_UPGRADE_RECOMMENDED);
76  if (upgrade_available_ == UPGRADE_NEEDED_OUTDATED_INSTALL) {
77    TriggerNotification(chrome::NOTIFICATION_OUTDATED_INSTALL);
78  } else if (upgrade_available_ == UPGRADE_NEEDED_OUTDATED_INSTALL_NO_AU) {
79    TriggerNotification(chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU);
80  } else if (upgrade_available_ == UPGRADE_AVAILABLE_CRITICAL ||
81             critical_experiment_updates_available_) {
82    TriggerCriticalUpdate();
83  }
84}
85
86void UpgradeDetector::TriggerCriticalUpdate() {
87  const base::TimeDelta idle_timer = UseTestingIntervals() ?
88      base::TimeDelta::FromSeconds(kIdleRepeatingTimerWait) :
89      base::TimeDelta::FromMinutes(kIdleRepeatingTimerWait);
90  idle_check_timer_.Start(FROM_HERE, idle_timer, this,
91                          &UpgradeDetector::CheckIdle);
92}
93
94void UpgradeDetector::CheckIdle() {
95  // CalculateIdleState expects an interval in seconds.
96  int idle_time_allowed = UseTestingIntervals() ? kIdleAmount :
97                                                  kIdleAmount * 60 * 60;
98
99  CalculateIdleState(
100      idle_time_allowed, base::Bind(&UpgradeDetector::IdleCallback,
101                                    base::Unretained(this)));
102}
103
104void UpgradeDetector::TriggerNotification(chrome::NotificationType type) {
105  content::NotificationService::current()->Notify(
106      type,
107      content::Source<UpgradeDetector>(this),
108      content::NotificationService::NoDetails());
109}
110
111void UpgradeDetector::IdleCallback(IdleState state) {
112  // Don't proceed while an incognito window is open. The timer will still
113  // keep firing, so this function will get a chance to re-evaluate this.
114  if (chrome::IsOffTheRecordSessionActive())
115    return;
116
117  switch (state) {
118    case IDLE_STATE_LOCKED:
119      // Computer is locked, auto-restart.
120      idle_check_timer_.Stop();
121      chrome::AttemptRestart();
122      break;
123    case IDLE_STATE_IDLE:
124      // Computer has been idle for long enough, show warning.
125      idle_check_timer_.Stop();
126      TriggerNotification(chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED);
127      break;
128    case IDLE_STATE_ACTIVE:
129    case IDLE_STATE_UNKNOWN:
130      break;
131    default:
132      NOTREACHED();  // Need to add any new value above (either providing
133                     // automatic restart or show notification to user).
134      break;
135  }
136}
137