summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd17
-rw-r--r--chrome/app/theme/theme_resources.grd5
-rw-r--r--chrome/browser/app_menu_model.cc45
-rw-r--r--chrome/browser/app_menu_model.h8
-rw-r--r--chrome/browser/browser.cc14
-rw-r--r--chrome/browser/browser.h1
-rw-r--r--chrome/browser/browser_prefs.cc4
-rw-r--r--chrome/browser/browser_shutdown.cc25
-rw-r--r--chrome/browser/browser_window.h3
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.h1
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.mm4
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc4
-rw-r--r--chrome/browser/gtk/browser_window_gtk.h1
-rw-r--r--chrome/browser/upgrade_detector.cc96
-rw-r--r--chrome/browser/upgrade_detector.h57
-rw-r--r--chrome/browser/views/frame/browser_view.cc10
-rw-r--r--chrome/browser/views/frame/browser_view.h5
-rw-r--r--chrome/browser/views/toolbar_view.cc112
-rw-r--r--chrome/browser/views/toolbar_view.h27
-rw-r--r--chrome/browser/views/update_recommended_message_box.cc90
-rw-r--r--chrome/browser/views/update_recommended_message_box.h49
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/common/notification_type.h16
-rw-r--r--chrome/common/pref_names.cc5
-rw-r--r--chrome/common/pref_names.h2
-rw-r--r--chrome/test/test_browser_window.h1
26 files changed, 586 insertions, 20 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 814e228..1ccfad1 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -985,6 +985,9 @@ each locale. -->
<message name="IDS_ABOUT" desc="The text label of the About Chrome menu item">
About &amp;<ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
</message>
+ <message name="IDS_UPDATE_NOW" desc="The text label of the Update Chrome Now menu item">
+ Update &amp;<ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
+ </message>
<message name="IDS_EXIT" desc="The text label of the Exit menu item">
E&amp;xit
</message>
@@ -1020,6 +1023,9 @@ each locale. -->
<message name="IDS_ABOUT" desc="In Title Case: The text label of the About Chrome menu item">
About &amp;<ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
</message>
+ <message name="IDS_UPDATE_NOW" desc="The text label of the Update Chrome Now menu item">
+ Update &amp;<ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
+ </message>
<message name="IDS_EXIT" desc="In Title Case: The text label of the Exit menu item">
E&amp;xit
</message>
@@ -7210,6 +7216,17 @@ Keep your key file in a safe place. You will need it to create new versions of y
Loading...
</message>
+ <!-- Update Recommended dialog -->
+ <message name="IDS_UPDATE_RECOMMENDED" desc="The main text of the Update Recommended dialog.">
+ Old school's not cool. <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is woefully out of date because it hasn't crashed or restarted in at least two weeks. Restart to apply update.
+ </message>
+ <message name="IDS_RESTART_AND_UPDATE" desc="The button label for restarting and updating Chrome.">
+ Restart and update
+ </message>
+ <message name="IDS_NOT_NOW" desc="The button label for delaying the restart and updating Chrome.">
+ Not now
+ </message>
+
<!-- Extra Mac UI Strings -->
<if expr="os == 'darwin'">
<message name="IDS_PLEASE_RESTART_BROWSER" desc="Title of the alert when Chrome needs to be restart for a change/update to take effect.">
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 126b546..5c6b2a1 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -345,6 +345,11 @@
<include name="IDR_SIDETABS_SHADOW_MIDDLE" file="sidetabs_shadow_middle.png" type="BINDATA" />
<include name="IDR_SIDETABS_SHADOW_BOTTOM" file="sidetabs_shadow_bottom.png" type="BINDATA" />
+ <!-- Upgrade notification -->
+
+ <include name="IDR_UPGRADE_DOT_INACTIVE" file="upgrade_dot_inactive.png" type="BINDATA" />
+ <include name="IDR_UPGRADE_DOT_ACTIVE" file="upgrade_dot_active.png" type="BINDATA" />
+
<!-- Geolocation -->
<include name="IDR_GEOLOCATION_INFOBAR_ICON" file="geolocation_infobar_icon.png" type="BINDATA" />
<include name="IDR_GEOLOCATION_ALLOWED_LOCATIONBAR_ICON" file="geolocation_allowed_locationbar_icon.png" type="BINDATA" />
diff --git a/chrome/browser/app_menu_model.cc b/chrome/browser/app_menu_model.cc
index a4cb383..ac418b7 100644
--- a/chrome/browser/app_menu_model.cc
+++ b/chrome/browser/app_menu_model.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
#include "base/command_line.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
@@ -14,9 +15,11 @@
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_ui_util.h"
+#include "chrome/browser/upgrade_detector.h"
#include "chrome/common/chrome_switches.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
AppMenuModel::AppMenuModel(menus::SimpleMenuModel::Delegate* delegate,
Browser* browser)
@@ -29,12 +32,33 @@ AppMenuModel::~AppMenuModel() {
}
bool AppMenuModel::IsLabelDynamicAt(int index) const {
- return IsSyncItem(index) || SimpleMenuModel::IsLabelDynamicAt(index);
+ return IsDynamicItem(index) || SimpleMenuModel::IsLabelDynamicAt(index);
}
string16 AppMenuModel::GetLabelAt(int index) const {
- return IsSyncItem(index) ?
- GetSyncMenuLabel() : SimpleMenuModel::GetLabelAt(index);
+ if (!IsDynamicItem(index))
+ return SimpleMenuModel::GetLabelAt(index);
+
+ int command_id = GetCommandIdAt(index);
+
+ switch (command_id) {
+ case IDC_ABOUT: return GetAboutEntryMenuLabel(); break;
+ case IDC_SYNC_BOOKMARKS: return GetSyncMenuLabel(); break;
+ default:
+ NOTREACHED();
+ return string16();
+ }
+}
+
+bool AppMenuModel::GetIconAt(int index, SkBitmap* icon) const {
+ if (GetCommandIdAt(index) == IDC_ABOUT &&
+ Singleton<UpgradeDetector>::get()->notify_upgrade()) {
+ // Show the exclamation point next to the menu item.
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ *icon = *rb.GetBitmapNamed(IDR_UPDATE_AVAILABLE);
+ return true;
+ }
+ return false;
}
void AppMenuModel::Build() {
@@ -160,6 +184,17 @@ string16 AppMenuModel::GetSyncMenuLabel() const {
browser_->profile()->GetOriginalProfile()->GetProfileSyncService());
}
-bool AppMenuModel::IsSyncItem(int index) const {
- return GetCommandIdAt(index) == IDC_SYNC_BOOKMARKS;
+string16 AppMenuModel::GetAboutEntryMenuLabel() const {
+ if (Singleton<UpgradeDetector>::get()->notify_upgrade()) {
+ return l10n_util::GetStringFUTF16(
+ IDS_UPDATE_NOW, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ }
+ return l10n_util::GetStringFUTF16(
+ IDS_ABOUT, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+}
+
+bool AppMenuModel::IsDynamicItem(int index) const {
+ int command_id = GetCommandIdAt(index);
+ return command_id == IDC_SYNC_BOOKMARKS ||
+ command_id == IDC_ABOUT;
}
diff --git a/chrome/browser/app_menu_model.h b/chrome/browser/app_menu_model.h
index b0daac7..962368e 100644
--- a/chrome/browser/app_menu_model.h
+++ b/chrome/browser/app_menu_model.h
@@ -22,10 +22,11 @@ class AppMenuModel : public menus::SimpleMenuModel {
Browser* browser);
virtual ~AppMenuModel();
- // Override this to handle the sync menu item (whose label is
- // updated dynamically).
+ // Overridden from menus::SimpleMenuModel:
virtual bool IsLabelDynamicAt(int index) const;
virtual string16 GetLabelAt(int index) const;
+ virtual bool HasIcons() const { return true; }
+ virtual bool GetIconAt(int index, SkBitmap* icon) const;
// Build/update profile submenu. Return true if profiles submenu is built or
// updated. False otherwise.
@@ -37,7 +38,8 @@ class AppMenuModel : public menus::SimpleMenuModel {
bool ProfilesChanged(const std::vector<std::wstring>& profiles) const;
string16 GetSyncMenuLabel() const;
- bool IsSyncItem(int index) const;
+ string16 GetAboutEntryMenuLabel() const;
+ bool IsDynamicItem(int index) const;
// Contents of the profiles menu to populate with profile names.
scoped_ptr<menus::SimpleMenuModel> profiles_menu_contents_;
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index e2b2ed3..e25da85 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -74,6 +74,7 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tab_menu_model.h"
+#include "chrome/browser/upgrade_detector.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/window_sizer.h"
#include "chrome/common/chrome_constants.h"
@@ -129,7 +130,6 @@ static const std::string kBrokenPageUrl =
"http://www.google.com/support/chrome/bin/request.py?contact_type="
"broken_website&format=inproduct&p.page_title=$1&p.page_url=$2";
-
///////////////////////////////////////////////////////////////////////////////
namespace {
@@ -1748,6 +1748,11 @@ void Browser::OpenAboutChromeDialog() {
window_->ShowAboutChromeDialog();
}
+void Browser::OpenUpdateChromeDialog() {
+ UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_);
+ window_->ShowUpdateChromeDialog();
+}
+
void Browser::OpenHelpTab() {
GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kHelpContentUrl));
AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK,
@@ -2025,7 +2030,12 @@ void Browser::ExecuteCommandWithDisposition(
case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
- case IDC_ABOUT: OpenAboutChromeDialog(); break;
+ case IDC_ABOUT:
+ if (Singleton<UpgradeDetector>::get()->notify_upgrade())
+ OpenUpdateChromeDialog();
+ else
+ OpenAboutChromeDialog();
+ break;
case IDC_HELP_PAGE: OpenHelpTab(); break;
#if defined(OS_CHROMEOS)
case IDC_SYSTEM_OPTIONS: OpenSystemOptionsDialog(); break;
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index 252e9f1..4fe3694 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -532,6 +532,7 @@ class Browser : public TabStripModelDelegate,
void OpenSyncMyBookmarksDialog();
void OpenImportSettingsDialog();
void OpenAboutChromeDialog();
+ void OpenUpdateChromeDialog();
void OpenHelpTab();
// Used by the "Get themes" link in the options dialog.
void OpenThemeGalleryTabAndActivate();
diff --git a/chrome/browser/browser_prefs.cc b/chrome/browser/browser_prefs.cc
index 891d1f5..1dc0463 100644
--- a/chrome/browser/browser_prefs.cc
+++ b/chrome/browser/browser_prefs.cc
@@ -43,6 +43,7 @@
#if defined(TOOLKIT_VIEWS) // TODO(port): whittle this down as we port
#include "chrome/browser/views/browser_actions_container.h"
#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/browser/views/update_recommended_message_box.h"
#endif
#if defined(TOOLKIT_GTK)
@@ -79,6 +80,9 @@ void RegisterLocalState(PrefService* local_state) {
#if defined(TOOLKIT_VIEWS)
BrowserView::RegisterBrowserViewPrefs(local_state);
#endif
+#if defined(OS_WIN)
+ UpdateRecommendedMessageBox::RegisterUpdateRecommendedPrefs(local_state);
+#endif
TaskManager::RegisterPrefs(local_state);
CookiePromptModalDialog::RegisterPrefs(local_state);
geolocation::RegisterPrefs(local_state);
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index c052790..af5bc26 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -28,6 +28,7 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "net/dns_global.h"
@@ -128,6 +129,14 @@ void Shutdown() {
shutdown_num_processes_slow_);
}
+ // Check local state for the restart flag so we can restart the session below.
+ bool restart_last_session = false;
+ if (prefs->HasPrefPath(prefs::kRestartLastSessionOnShutdown)) {
+ restart_last_session =
+ prefs->GetBoolean(prefs::kRestartLastSessionOnShutdown);
+ prefs->ClearPref(prefs::kRestartLastSessionOnShutdown);
+ }
+
prefs->SavePersistentPrefs();
#if defined(OS_WIN)
@@ -152,6 +161,20 @@ void Shutdown() {
shutdown_type_ != browser_shutdown::END_SESSION) {
Upgrade::SwapNewChromeExeIfPresent();
}
+
+ if (restart_last_session) {
+ // Make sure to relaunch the browser with the same command line and add
+ // Restore Last Session flag if session restore is not set.
+ CommandLine command_line = CommandLine::FromString(
+ CommandLine::ForCurrentProcess()->command_line_string());
+ if (!command_line.HasSwitch(switches::kRestoreLastSession))
+ command_line.AppendSwitch(switches::kRestoreLastSession);
+ Upgrade::RelaunchChromeBrowser(command_line);
+ }
+#endif
+#if !defined(OS_WIN)
+ if (restart_last_session)
+ NOTIMPLEMENTED();
#endif
if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) {
diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h
index ad10784..93ae25f 100644
--- a/chrome/browser/browser_window.h
+++ b/chrome/browser/browser_window.h
@@ -183,6 +183,9 @@ class BrowserWindow {
// Shows the About Chrome dialog box.
virtual views::Window* ShowAboutChromeDialog() = 0;
+ // Shows the Update Recommended dialog box.
+ virtual void ShowUpdateChromeDialog() = 0;
+
// Shows the Task manager.
virtual void ShowTaskManager() = 0;
diff --git a/chrome/browser/cocoa/browser_window_cocoa.h b/chrome/browser/cocoa/browser_window_cocoa.h
index b50feb9..91fb085 100644
--- a/chrome/browser/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/cocoa/browser_window_cocoa.h
@@ -67,6 +67,7 @@ class BrowserWindowCocoa : public BrowserWindow,
virtual void ToggleBookmarkBar();
virtual void ToggleExtensionShelf();
virtual views::Window* ShowAboutChromeDialog();
+ virtual void ShowUpdateChromeDialog();
virtual void ShowTaskManager();
virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked);
virtual bool IsDownloadShelfVisible() const;
diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm
index 821e35f..58a62bc 100644
--- a/chrome/browser/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/cocoa/browser_window_cocoa.mm
@@ -259,6 +259,10 @@ views::Window* BrowserWindowCocoa::ShowAboutChromeDialog() {
return NULL;
}
+void BrowserWindowCocoa::ShowUpdateChromeDialog() {
+ NOTIMPLEMENTED();
+}
+
void BrowserWindowCocoa::ShowTaskManager() {
TaskManagerMac::Show();
}
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index e5ac25e..5c32ca7 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -883,6 +883,10 @@ views::Window* BrowserWindowGtk::ShowAboutChromeDialog() {
return NULL;
}
+void BrowserWindowGtk::ShowUpdateChromeDialog() {
+ NOTIMPLEMENTED();
+}
+
void BrowserWindowGtk::ShowTaskManager() {
TaskManagerGtk::Show();
}
diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h
index 3404f3b..fdbf27c 100644
--- a/chrome/browser/gtk/browser_window_gtk.h
+++ b/chrome/browser/gtk/browser_window_gtk.h
@@ -85,6 +85,7 @@ class BrowserWindowGtk : public BrowserWindow,
virtual void ToggleBookmarkBar();
virtual void ToggleExtensionShelf();
virtual views::Window* ShowAboutChromeDialog();
+ virtual void ShowUpdateChromeDialog();
virtual void ShowTaskManager();
virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked);
virtual bool IsDownloadShelfVisible() const;
diff --git a/chrome/browser/upgrade_detector.cc b/chrome/browser/upgrade_detector.cc
new file mode 100644
index 0000000..3aedb9a
--- /dev/null
+++ b/chrome/browser/upgrade_detector.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/upgrade_detector.h"
+
+#include "base/file_version_info.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "base/version.h"
+#include "chrome/app/chrome_version_info.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/installer/util/browser_distribution.h"
+
+#if defined(OS_WIN)
+#include "chrome/installer/util/install_util.h"
+#endif
+
+// TODO(finnur): For the stable channel we want to check daily and notify
+// the user if more than 2 weeks have passed since the upgrade happened
+// (without a reboot). For the dev channel however, I want quicker feedback
+// on how the feature works so I'm checking every hour and notifying the
+// user immediately.
+
+// How often to check for an upgrade.
+static int kCheckForUpgradeEveryMs = 60 * 60 * 1000; // 1 hour.
+
+// How long to wait before notifying the user about the upgrade.
+static int kNotifyUserAfterMs = 0;
+
+UpgradeDetector::UpgradeDetector() : upgrade_detected_(false) {
+#if !defined(OS_WIN)
+ return;
+#endif
+
+ detect_upgrade_timer_.Start(
+ base::TimeDelta::FromMilliseconds(kCheckForUpgradeEveryMs),
+ this, &UpgradeDetector::CheckForUpgrade);
+}
+
+UpgradeDetector::~UpgradeDetector() {
+}
+
+void UpgradeDetector::CheckForUpgrade() {
+#if defined(OS_WIN)
+ using installer::Version;
+
+ // Get the version of the currently *installed* instance of Chrome,
+ // which might be newer than the *running* instance if we have been
+ // upgraded in the background.
+ Version* installed_version = InstallUtil::GetChromeVersion(false);
+ if (!installed_version) {
+ // User level Chrome is not installed, check system level.
+ installed_version = InstallUtil::GetChromeVersion(true);
+ }
+
+ // Get the version of the currently *running* instance of Chrome.
+ scoped_ptr<FileVersionInfo> version(chrome_app::GetChromeVersionInfo());
+ if (version.get() == NULL) {
+ NOTREACHED() << L"Failed to get current file version";
+ return;
+ }
+ scoped_ptr<Version> running_version(Version::GetVersionFromString(
+ version->file_version()));
+
+ if (installed_version->IsHigherThan(running_version.get())) {
+ // Stop the recurring timer (that is checking for changes).
+ detect_upgrade_timer_.Stop();
+
+ upgrade_detected_ = true;
+
+ NotificationService::current()->Notify(
+ NotificationType::UPGRADE_DETECTED,
+ Source<UpgradeDetector>(this),
+ NotificationService::NoDetails());
+
+ // Start the OneShot timer for notifying the user after a certain period.
+ upgrade_notification_timer_.Start(
+ base::TimeDelta::FromMilliseconds(kNotifyUserAfterMs),
+ this, &UpgradeDetector::NotifyOnUpgrade);
+ }
+#else
+ DCHECK(kNotifyUserAfterMs > 0); // Avoid error: var defined but not used.
+ NOTIMPLEMENTED();
+#endif
+}
+
+void UpgradeDetector::NotifyOnUpgrade() {
+ notify_upgrade_ = true;
+
+ NotificationService::current()->Notify(
+ NotificationType::UPGRADE_RECOMMENDED,
+ Source<UpgradeDetector>(this),
+ NotificationService::NoDetails());
+}
diff --git a/chrome/browser/upgrade_detector.h b/chrome/browser/upgrade_detector.h
new file mode 100644
index 0000000..9a7da11
--- /dev/null
+++ b/chrome/browser/upgrade_detector.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UPGRADE_DETECTOR_H_
+#define CHROME_BROWSER_UPGRADE_DETECTOR_H_
+
+#include "base/singleton.h"
+#include "base/timer.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// UpgradeDetector
+//
+// This class is a singleton class that monitors when an upgrade happens in the
+// background. We basically ask Omaha what it thinks the latest version is and
+// if our version is lower we send out a notification upon:
+// a) Detecting an upgrade and...
+// b) When we think the user should be notified about the upgrade.
+// The latter happens much later, since we don't want to be too annoying.
+//
+class UpgradeDetector {
+ public:
+ ~UpgradeDetector();
+
+ bool notify_upgrade() { return notify_upgrade_; }
+
+ private:
+ UpgradeDetector();
+ friend struct DefaultSingletonTraits<UpgradeDetector>;
+
+ // Checks with Omaha if we have the latest version. If not, sends out a
+ // notification and starts a one shot timer to wait until notifying the
+ // user.
+ void CheckForUpgrade();
+
+ // The function that sends out a notification (after a certain time has
+ // elapsed) that lets the rest of the UI know we should start notifying the
+ // user that a new version is available.
+ void NotifyOnUpgrade();
+
+ // We periodically check to see if Chrome has been upgraded.
+ base::RepeatingTimer<UpgradeDetector> detect_upgrade_timer_;
+
+ // After we detect an upgrade we wait a set time before notifying the user.
+ base::OneShotTimer<UpgradeDetector> upgrade_notification_timer_;
+
+ // Whether we have detected an upgrade happening while we were running.
+ bool upgrade_detected_;
+
+ // Whether we have waited long enough after detecting an upgrade (to see
+ // is we should start nagging about upgrading).
+ bool notify_upgrade_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpgradeDetector);
+};
+
+#endif // CHROME_BROWSER_UPGRADE_DETECTOR_H_
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index 2d36e9c..3dc71af 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -42,6 +42,7 @@
#include "chrome/browser/views/tabs/side_tab_strip.h"
#include "chrome/browser/views/theme_install_bubble_view.h"
#include "chrome/browser/views/toolbar_view.h"
+#include "chrome/browser/views/update_recommended_message_box.h"
#include "chrome/browser/window_sizer.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_resource.h"
@@ -966,6 +967,12 @@ views::Window* BrowserView::ShowAboutChromeDialog() {
browser_->profile());
}
+void BrowserView::ShowUpdateChromeDialog() {
+#if defined(OS_WIN)
+ UpdateRecommendedMessageBox::ShowMessageBox(GetWindow()->GetNativeWindow());
+#endif
+}
+
void BrowserView::ShowTaskManager() {
browser::ShowTaskManager();
}
@@ -980,9 +987,10 @@ void BrowserView::SetDownloadShelfVisible(bool visible) {
if (browser_ == NULL)
return;
- if (visible && IsDownloadShelfVisible() != visible)
+ if (visible && IsDownloadShelfVisible() != visible) {
// Invoke GetDownloadShelf to force the shelf to be created.
GetDownloadShelf();
+ }
if (browser_ != NULL)
browser_->UpdateDownloadShelfVisibility(visible);
diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h
index 0f2f12c..2d62c77 100644
--- a/chrome/browser/views/frame/browser_view.h
+++ b/chrome/browser/views/frame/browser_view.h
@@ -295,6 +295,7 @@ class BrowserView : public BrowserBubbleHost,
virtual void ToggleBookmarkBar();
virtual void ToggleExtensionShelf();
virtual views::Window* ShowAboutChromeDialog();
+ virtual void ShowUpdateChromeDialog();
virtual void ShowTaskManager();
virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked);
virtual void SetDownloadShelfVisible(bool visible);
@@ -597,9 +598,9 @@ class BrowserView : public BrowserBubbleHost,
UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
scoped_ptr<AccessibleViewHelper> accessible_view_helper_;
- #if defined(OS_LINUX)
+#if defined(OS_LINUX)
scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;
- #endif
+#endif
// Loads extension_app_icon_ asynchronously on the file thread.
ImageLoadingTracker extension_app_icon_loader_;
diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc
index cc00ba5..4d15f5c 100644
--- a/chrome/browser/views/toolbar_view.cc
+++ b/chrome/browser/views/toolbar_view.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/upgrade_detector.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/bookmark_menu_button.h"
#include "chrome/browser/views/browser_actions_container.h"
@@ -24,6 +25,7 @@
#include "gfx/canvas.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "gfx/skbitmap_operations.h"
#include "grit/theme_resources.h"
#include "views/controls/button/button_dropdown.h"
#include "views/focus/view_storage.h"
@@ -36,6 +38,16 @@ static const int kControlVertOffset = 6;
static const int kControlIndent = 3;
static const int kStatusBubbleWidth = 480;
+// The length of time to run the upgrade notification animation (the time it
+// takes one pulse to run its course and go back to its original brightness).
+static const int kPulseDuration = 2000;
+
+// How long to wait between pulsating the upgrade notifier.
+static const int kPulsateEveryMs = 8000;
+
+// The offset in pixels of the upgrade dot on the app menu.
+static const int kUpgradeDotOffset = 11;
+
// Separation between the location bar and the menus.
static const int kMenuButtonOffset = 3;
@@ -89,6 +101,12 @@ ToolbarView::ToolbarView(Browser* browser)
kPopupBackgroundEdge = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_LOCATIONBG_POPUPMODE_EDGE);
}
+
+ if (!Singleton<UpgradeDetector>::get()->notify_upgrade()) {
+ registrar_.Add(this,
+ NotificationType::UPGRADE_RECOMMENDED,
+ NotificationService::AllSources());
+ }
}
ToolbarView::~ToolbarView() {
@@ -280,6 +298,14 @@ void ToolbarView::OnInputInProgress(bool in_progress) {
}
////////////////////////////////////////////////////////////////////////////////
+// ToolbarView, AnimationDelegate implementation:
+
+void ToolbarView::AnimationProgressed(const Animation* animation) {
+ app_menu_->SetIcon(GetAppMenuIcon());
+ SchedulePaint();
+}
+
+////////////////////////////////////////////////////////////////////////////////
// ToolbarView, CommandUpdater::CommandObserver implementation:
void ToolbarView::EnabledStateChangedForCommand(int id, bool enabled) {
@@ -340,6 +366,8 @@ void ToolbarView::Observe(NotificationType type,
Layout();
SchedulePaint();
}
+ } else if (type == NotificationType::UPGRADE_RECOMMENDED) {
+ ShowUpgradeReminder();
}
}
@@ -665,6 +693,10 @@ void ToolbarView::CreateRightSideControls(Profile* profile) {
bookmark_menu_ = NULL;
}
+ // Catch the case where the window is created after we detect a new version.
+ if (Singleton<UpgradeDetector>::get()->notify_upgrade())
+ ShowUpgradeReminder();
+
LoadRightSideControlsImages();
AddChildView(browser_actions_);
@@ -734,6 +766,77 @@ void ToolbarView::LoadCenterStackImages() {
tp->GetBitmapNamed(IDR_GO_MASK));
}
+void ToolbarView::ShowUpgradeReminder() {
+ update_reminder_animation_.reset(new SlideAnimation(this));
+ update_reminder_animation_->SetSlideDuration(kPulseDuration);
+
+ // Then start the recurring timer for pulsating it.
+ upgrade_reminder_pulse_timer_.Start(
+ base::TimeDelta::FromMilliseconds(kPulsateEveryMs),
+ this, &ToolbarView::PulsateUpgradeNotifier);
+}
+
+void ToolbarView::PulsateUpgradeNotifier() {
+ // Start the pulsating animation.
+ update_reminder_animation_->Reset(0.0);
+ update_reminder_animation_->Show();
+}
+
+SkBitmap ToolbarView::GetAppMenuIcon() {
+ ThemeProvider* tp = GetThemeProvider();
+
+ SkBitmap icon;
+
+ // We use different menu button images if the locale is right-to-left.
+ if (base::i18n::IsRTL())
+ icon = *tp->GetBitmapNamed(IDR_MENU_CHROME_RTL);
+ else
+ icon = *tp->GetBitmapNamed(IDR_MENU_CHROME);
+
+ if (!Singleton<UpgradeDetector>::get()->notify_upgrade())
+ return icon;
+
+ // Draw the chrome app menu icon onto the canvas.
+ scoped_ptr<gfx::Canvas> canvas(
+ new gfx::Canvas(icon.width(), icon.height(), false));
+ canvas->DrawBitmapInt(icon, 0, 0);
+
+ SkBitmap badge;
+
+ static bool has_faded_in = false;
+ if (!has_faded_in) {
+ SkBitmap* dot = tp->GetBitmapNamed(IDR_UPGRADE_DOT_INACTIVE);
+ SkBitmap transparent;
+ transparent.setConfig(dot->getConfig(), dot->width(), dot->height());
+ transparent.allocPixels();
+ transparent.eraseARGB(0, 0, 0, 0);
+ badge = SkBitmapOperations::CreateBlendedBitmap(
+ *dot, transparent, 1.0 - update_reminder_animation_->GetCurrentValue());
+ if (update_reminder_animation_->GetCurrentValue() == 1.0)
+ has_faded_in = true;
+ } else {
+ // Convert animation values that start from 0.0 and incrementally go
+ // up to 1.0 into values that start in 0.0, go to 1.0 and then back
+ // to 0.0 (to create a pulsing effect).
+ double value = 1.0 -
+ abs(2.0 * update_reminder_animation_->GetCurrentValue() -
+ 1.0);
+
+ // Add the badge to it.
+ badge = SkBitmapOperations::CreateBlendedBitmap(
+ *tp->GetBitmapNamed(IDR_UPGRADE_DOT_INACTIVE),
+ *tp->GetBitmapNamed(IDR_UPGRADE_DOT_ACTIVE),
+ value);
+ }
+
+ int x_pos = kUpgradeDotOffset;
+ if (base::i18n::IsRTL())
+ x_pos = icon.width() - badge.width();
+ canvas->DrawBitmapInt(badge, x_pos, icon.height() - badge.height());
+
+ return canvas->ExtractBitmap();
+}
+
void ToolbarView::LoadRightSideControlsImages() {
ThemeProvider* tp = GetThemeProvider();
@@ -742,10 +845,8 @@ void ToolbarView::LoadRightSideControlsImages() {
page_menu_->SetIcon(*tp->GetBitmapNamed(IDR_MENU_PAGE_RTL));
else
page_menu_->SetIcon(*tp->GetBitmapNamed(IDR_MENU_PAGE));
- if (base::i18n::IsRTL())
- app_menu_->SetIcon(*tp->GetBitmapNamed(IDR_MENU_CHROME_RTL));
- else
- app_menu_->SetIcon(*tp->GetBitmapNamed(IDR_MENU_CHROME));
+
+ app_menu_->SetIcon(GetAppMenuIcon());
if (bookmark_menu_ != NULL)
bookmark_menu_->SetIcon(*tp->GetBitmapNamed(IDR_MENU_BOOKMARK));
@@ -789,6 +890,9 @@ void ToolbarView::RunAppMenu(const gfx::Point& pt) {
destroyed_flag_ = NULL;
+ // Stop pulsating the upgrade reminder on the app menu, if active.
+ upgrade_reminder_pulse_timer_.Stop();
+
for (unsigned int i = 0; i < menu_listeners_.size(); i++) {
app_menu_menu_->RemoveMenuListener(menu_listeners_[i]);
}
diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h
index 9c7b472..99e1d28 100644
--- a/chrome/browser/views/toolbar_view.h
+++ b/chrome/browser/views/toolbar_view.h
@@ -8,6 +8,7 @@
#include <vector>
#include "app/menus/simple_menu_model.h"
+#include "app/slide_animation.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/app_menu_model.h"
#include "chrome/browser/back_forward_menu_model.h"
@@ -38,6 +39,7 @@ class ToolbarView : public AccessibleToolbarView,
public views::FocusChangeListener,
public menus::SimpleMenuModel::Delegate,
public LocationBarView::Delegate,
+ public AnimationDelegate,
public NotificationObserver,
public CommandUpdater::CommandObserver,
public views::ButtonListener {
@@ -107,6 +109,9 @@ class ToolbarView : public AccessibleToolbarView,
virtual TabContents* GetTabContents();
virtual void OnInputInProgress(bool in_progress);
+ // Overridden from AnimationDelegate:
+ virtual void AnimationProgressed(const Animation* animation);
+
// Overridden from CommandUpdater::CommandObserver:
virtual void EnabledStateChangedForCommand(int id, bool enabled);
@@ -173,6 +178,17 @@ class ToolbarView : public AccessibleToolbarView,
// was called.
void RestoreLastFocusedView();
+ // Starts the recurring timer that periodically asks the upgrade notifier
+ // to pulsate.
+ void ShowUpgradeReminder();
+
+ // Show the reminder, tempting the user to upgrade by pulsating.
+ void PulsateUpgradeNotifier();
+
+ // Gets a canvas with the icon for the app menu. It will possibly contain
+ // an overlaid badge if an update is recommended.
+ SkBitmap GetAppMenuIcon();
+
scoped_ptr<BackForwardMenuModel> back_menu_model_;
scoped_ptr<BackForwardMenuModel> forward_menu_model_;
@@ -222,6 +238,13 @@ class ToolbarView : public AccessibleToolbarView,
// Vector of listeners to receive callbacks when the menu opens.
std::vector<views::MenuListener*> menu_listeners_;
+ // The animation that makes the update reminder pulse.
+ scoped_ptr<SlideAnimation> update_reminder_animation_;
+
+ // We periodically restart the animation after it has been showed
+ // once, to create a pulsating effect.
+ base::RepeatingTimer<ToolbarView> upgrade_reminder_pulse_timer_;
+
// Are we in the menu bar emulation mode, where the app and page menu
// are temporarily focusable?
bool menu_bar_emulation_mode_;
@@ -229,7 +252,9 @@ class ToolbarView : public AccessibleToolbarView,
// Used to post tasks to switch to the next/previous menu.
ScopedRunnableMethodFactory<ToolbarView> method_factory_;
- // If non-null the destuctor sets this to true. This is set to a non-null
+ NotificationRegistrar registrar_;
+
+ // If non-null the destructor sets this to true. This is set to a non-null
// while the menu is showing and used to detect if the menu was deleted while
// running.
bool* destroyed_flag_;
diff --git a/chrome/browser/views/update_recommended_message_box.cc b/chrome/browser/views/update_recommended_message_box.cc
new file mode 100644
index 0000000..dc1bf05
--- /dev/null
+++ b/chrome/browser/views/update_recommended_message_box.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/views/update_recommended_message_box.h"
+
+#include "app/l10n_util.h"
+#include "app/message_box_flags.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/pref_service.h"
+#include "chrome/common/pref_names.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "views/controls/message_box_view.h"
+#include "views/window/window.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// UpdateRecommendedMessageBox, public:
+
+// static
+void UpdateRecommendedMessageBox::ShowMessageBox(
+ gfx::NativeWindow parent_window) {
+ // When the window closes, it will delete itself.
+ new UpdateRecommendedMessageBox(parent_window);
+}
+
+void UpdateRecommendedMessageBox::RegisterUpdateRecommendedPrefs(
+ PrefService* prefs) {
+ prefs->RegisterBooleanPref(prefs::kRestartLastSessionOnShutdown, false);
+}
+
+bool UpdateRecommendedMessageBox::Accept() {
+ // Set the flag to restore the last session on shutdown.
+ PrefService* pref_service = g_browser_process->local_state();
+ pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true);
+
+ BrowserList::CloseAllBrowsersAndExit();
+
+ return true;
+}
+
+int UpdateRecommendedMessageBox::GetDialogButtons() const {
+ return MessageBoxFlags::DIALOGBUTTON_OK |
+ MessageBoxFlags::DIALOGBUTTON_CANCEL;
+}
+
+std::wstring UpdateRecommendedMessageBox::GetDialogButtonLabel(
+ MessageBoxFlags::DialogButton button) const {
+ DCHECK(button == MessageBoxFlags::DIALOGBUTTON_OK ||
+ button == MessageBoxFlags::DIALOGBUTTON_CANCEL);
+ return button == MessageBoxFlags::DIALOGBUTTON_OK ?
+ l10n_util::GetString(IDS_RESTART_AND_UPDATE) :
+ l10n_util::GetString(IDS_NOT_NOW);
+}
+
+std::wstring UpdateRecommendedMessageBox::GetWindowTitle() const {
+ return l10n_util::GetString(IDS_PRODUCT_NAME);
+}
+
+void UpdateRecommendedMessageBox::DeleteDelegate() {
+ delete this;
+}
+
+bool UpdateRecommendedMessageBox::IsModal() const {
+ return true;
+}
+
+views::View* UpdateRecommendedMessageBox::GetContentsView() {
+ return message_box_view_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// UpdateRecommendedMessageBox, private:
+
+UpdateRecommendedMessageBox::UpdateRecommendedMessageBox(
+ gfx::NativeWindow parent_window) {
+ const int kDialogWidth = 400;
+ // Also deleted when the window closes.
+ message_box_view_ = new MessageBoxView(
+ MessageBoxFlags::kFlagHasMessage | MessageBoxFlags::kFlagHasOKButton,
+ l10n_util::GetStringF(IDS_UPDATE_RECOMMENDED,
+ l10n_util::GetString(IDS_PRODUCT_NAME)),
+ std::wstring(),
+ kDialogWidth);
+ views::Window::CreateChromeWindow(parent_window, gfx::Rect(), this)->Show();
+}
+
+UpdateRecommendedMessageBox::~UpdateRecommendedMessageBox() {
+}
diff --git a/chrome/browser/views/update_recommended_message_box.h b/chrome/browser/views/update_recommended_message_box.h
new file mode 100644
index 0000000..9751db4
--- /dev/null
+++ b/chrome/browser/views/update_recommended_message_box.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VIEWS_UPDATE_RECOMMENDED_MESSAGE_BOX_H_
+#define CHROME_BROWSER_VIEWS_UPDATE_RECOMMENDED_MESSAGE_BOX_H_
+
+#include "base/basictypes.h"
+#include "gfx/native_widget_types.h"
+#include "views/window/dialog_delegate.h"
+
+class MessageBoxView;
+class PrefService;
+
+// A dialog box that tells the user that an update is recommended in order for
+// the latest version to be put to use.
+class UpdateRecommendedMessageBox : public views::DialogDelegate {
+ public:
+ // This box is modal to |parent_window|.
+ static void ShowMessageBox(gfx::NativeWindow parent_window);
+
+ // Register preferences specific to this view.
+ static void RegisterUpdateRecommendedPrefs(PrefService* prefs);
+
+ // Overridden from views::DialogDelegate:
+ virtual bool Accept();
+
+ protected:
+ // Overridden from views::DialogDelegate:
+ virtual int GetDialogButtons() const;
+ virtual std::wstring GetDialogButtonLabel(
+ MessageBoxFlags::DialogButton button) const;
+ virtual std::wstring GetWindowTitle() const;
+
+ // Overridden from views::WindowDelegate:
+ virtual void DeleteDelegate();
+ virtual bool IsModal() const;
+ virtual views::View* GetContentsView();
+
+ private:
+ explicit UpdateRecommendedMessageBox(gfx::NativeWindow parent_window);
+ virtual ~UpdateRecommendedMessageBox();
+
+ MessageBoxView* message_box_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateRecommendedMessageBox);
+};
+
+#endif // CHROME_BROWSER_VIEWS_UPDATE_RECOMMENDED_MESSAGE_BOX_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 6783f64..3423b49 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2190,6 +2190,8 @@
'browser/translate/translate_manager.h',
'browser/translate/translate_prefs.cc',
'browser/translate/translate_prefs.h',
+ 'browser/upgrade_detector.cc',
+ 'browser/upgrade_detector.h',
'browser/user_data_manager.cc',
'browser/user_data_manager.h',
'browser/user_style_sheet_watcher.cc',
@@ -2529,6 +2531,8 @@
'browser/views/url_picker.h',
'browser/views/unhandled_keyboard_event_handler.cc',
'browser/views/unhandled_keyboard_event_handler.h',
+ 'browser/views/update_recommended_message_box.cc',
+ 'browser/views/update_recommended_message_box.h',
'browser/views/user_data_dir_dialog.cc',
'browser/views/user_data_dir_dialog.h',
'browser/visitedlink_master.cc',
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index 17ccf04..de9efcb 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -889,6 +889,20 @@ class NotificationType {
// memory in use, no source or details are passed. See memory_purger.h .cc.
PURGE_MEMORY,
+ // Upgrade notifications ---------------------------------------------------
+
+ // Sent when Chrome detects that it has been upgraded behind the scenes.
+ // NOTE: The detection mechanism is asynchronous, so this event may arrive
+ // quite some time after the upgrade actually happened. No details are
+ // expected.
+ UPGRADE_DETECTED,
+
+ // Sent when Chrome believes an update has been installed and available for
+ // long enough with the user shutting down to let it take effect. See
+ // upgrade_detector.cc for details on how long it waits. No details are
+ // expected.
+ UPGRADE_RECOMMENDED,
+
// Accessibility Notifications ---------------------------------------------
// Notification that a window in the browser UI (not the web content)
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 51eaa01..a313944 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -705,6 +705,11 @@ const wchar_t kShutdownNumProcesses[] = L"shutdown.num_processes";
// Number of processes that were shut down using the slow path.
const wchar_t kShutdownNumProcessesSlow[] = L"shutdown.num_processes_slow";
+// Whether to restart the current Chrome session automatically as the last thing
+// before shutting everything down.
+const wchar_t kRestartLastSessionOnShutdown[] =
+ L"restart.last.session.on.shutdown";
+
// Number of bookmarks/folders on the bookmark bar/other bookmark folder.
const wchar_t kNumBookmarksOnBookmarkBar[] =
L"user_experience_metrics.num_bookmarks_on_bookmark_bar";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 9d84318..dc2199a 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -251,6 +251,8 @@ extern const wchar_t kShutdownType[];
extern const wchar_t kShutdownNumProcesses[];
extern const wchar_t kShutdownNumProcessesSlow[];
+extern const wchar_t kRestartLastSessionOnShutdown[];
+
extern const wchar_t kNumBookmarksOnBookmarkBar[];
extern const wchar_t kNumFoldersOnBookmarkBar[];
extern const wchar_t kNumBookmarksInOtherBookmarkFolder[];
diff --git a/chrome/test/test_browser_window.h b/chrome/test/test_browser_window.h
index 2e2ddcb..77874e6 100644
--- a/chrome/test/test_browser_window.h
+++ b/chrome/test/test_browser_window.h
@@ -69,6 +69,7 @@ class TestBrowserWindow : public BrowserWindow {
virtual void ToggleBookmarkBar() {}
virtual void ToggleExtensionShelf() {}
virtual views::Window* ShowAboutChromeDialog() { return NULL; }
+ virtual void ShowUpdateChromeDialog() {}
virtual void ShowTaskManager() {}
virtual void ShowBookmarkManager() {}
virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {}