When critical updates have been installed and the user has been idle for quite some time, show a bubble anchored to the wrench menu with a countdown clock for auto-restarting.

BUG=97665
TEST=The testing for this is a bit too long-windy to describe here. Contact me for details.
Review URL: http://codereview.chromium.org/8142028

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105298 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/upgrade_detector.cc b/chrome/browser/upgrade_detector.cc
index f4a7e68..eb6dfa5 100644
--- a/chrome/browser/upgrade_detector.cc
+++ b/chrome/browser/upgrade_detector.cc
@@ -4,12 +4,32 @@
 
 #include "chrome/browser/upgrade_detector.h"
 
+#include "base/bind.h"
+#include "base/command_line.h"
 #include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/common/notification_service.h"
 #include "grit/theme_resources.h"
 
+// How long to wait between checks for whether the user has been idle.
+static const int kIdleRepeatingTimerWait = 10;  // Minutes (seconds if testing).
+
+// How much idle time (since last input even was detected) must have passed
+// until we notify that a critical update has occurred.
+static const int kIdleAmount = 2;  // Hours (or seconds, if testing).
+
+bool UseTestingIntervals() {
+  // If a command line parameter specifying how long the upgrade check should
+  // be, we assume it is for testing and switch to using seconds instead of
+  // hours.
+  const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
+  return !cmd_line.GetSwitchValueASCII(
+      switches::kCheckForUpdateIntervalSec).empty();
+}
+
 // static
 void UpgradeDetector::RegisterPrefs(PrefService* prefs) {
   prefs->RegisterBooleanPref(prefs::kRestartLastSessionOnShutdown, false);
@@ -18,6 +38,13 @@
 int UpgradeDetector::GetIconResourceID(UpgradeNotificationIconType type) {
   bool badge = type == UPGRADE_ICON_TYPE_BADGE;
   switch (upgrade_notification_stage_) {
+    case UPGRADE_ANNOYANCE_CRITICAL:
+      // The critical annoyance state, somewhat ironically, re-purposes the
+      // icon for the second highest severity state, since that state has the
+      // icon most closely resembling the one requested of this feature and the
+      // critical annoyance is never part of the sliding scale of severity
+      // anyway (always shown on its own).
+      return badge ? IDR_UPDATE_BADGE3 : IDR_UPDATE_MENU3;
     case UPGRADE_ANNOYANCE_SEVERE:
       return badge ? IDR_UPDATE_BADGE4 : IDR_UPDATE_MENU4;
     case UPGRADE_ANNOYANCE_HIGH:
@@ -32,7 +59,9 @@
 }
 
 UpgradeDetector::UpgradeDetector()
-    : upgrade_notification_stage_(UPGRADE_ANNOYANCE_NONE),
+    : is_critical_upgrade_(false),
+      critical_update_acknowledged_(false),
+      upgrade_notification_stage_(UPGRADE_ANNOYANCE_NONE),
       notify_upgrade_(false) {
 }
 
@@ -41,6 +70,7 @@
 
 void UpgradeDetector::NotifyUpgradeDetected() {
   upgrade_detected_time_ = base::Time::Now();
+  critical_update_acknowledged_ = false;
 }
 
 void UpgradeDetector::NotifyUpgradeRecommended() {
@@ -50,4 +80,48 @@
       chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
       Source<UpgradeDetector>(this),
       NotificationService::NoDetails());
+
+  if (is_critical_upgrade_) {
+    int idle_timer = UseTestingIntervals() ?
+        kIdleRepeatingTimerWait :
+        kIdleRepeatingTimerWait * 60;  // To minutes.
+    idle_check_timer_.Start(FROM_HERE,
+        base::TimeDelta::FromSeconds(idle_timer),
+        this, &UpgradeDetector::CheckIdle);
+  }
+}
+
+void UpgradeDetector::CheckIdle() {
+  // CalculateIdleState expects an interval in seconds.
+  int idle_time_allowed = UseTestingIntervals() ? kIdleAmount :
+                                                  kIdleAmount * 60 * 60;
+
+  CalculateIdleState(
+      idle_time_allowed, base::Bind(&UpgradeDetector::IdleCallback,
+                                    base::Unretained(this)));
+}
+
+void UpgradeDetector::IdleCallback(IdleState state) {
+  switch (state) {
+    case IDLE_STATE_LOCKED:
+      // Computer is locked, auto-restart.
+      idle_check_timer_.Stop();
+      BrowserList::AttemptRestart();
+      break;
+    case IDLE_STATE_IDLE:
+      // Computer has been idle for long enough, show warning.
+      idle_check_timer_.Stop();
+      NotificationService::current()->Notify(
+          chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED,
+          Source<UpgradeDetector>(this),
+          NotificationService::NoDetails());
+      break;
+    case IDLE_STATE_ACTIVE:
+    case IDLE_STATE_UNKNOWN:
+      break;
+    default:
+      NOTREACHED();  // Need to add any new value above (either providing
+                     // automatic restart or show notification to user).
+      break;
+  }
 }