OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <string> | 5 #include <string> |
6 | 6 |
7 #include "base/base_paths.h" | 7 #include "base/base_paths.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
(...skipping 12 matching lines...) Expand all Loading... | |
23 #include "chrome/common/pref_names.h" | 23 #include "chrome/common/pref_names.h" |
24 #include "content/browser/user_metrics.h" | 24 #include "content/browser/user_metrics.h" |
25 #include "content/common/notification_service.h" | 25 #include "content/common/notification_service.h" |
26 #include "content/common/notification_type.h" | 26 #include "content/common/notification_type.h" |
27 #include "grit/chromium_strings.h" | 27 #include "grit/chromium_strings.h" |
28 #include "grit/generated_resources.h" | 28 #include "grit/generated_resources.h" |
29 #include "grit/theme_resources.h" | 29 #include "grit/theme_resources.h" |
30 #include "ui/base/l10n/l10n_util.h" | 30 #include "ui/base/l10n/l10n_util.h" |
31 #include "ui/base/resource/resource_bundle.h" | 31 #include "ui/base/resource/resource_bundle.h" |
32 | 32 |
33 void BackgroundModeManager::OnApplicationDataChanged( | 33 |
34 const Extension* extension) { | 34 BackgroundModeManager::BackgroundModeData::BackgroundModeData( |
35 UpdateContextMenuEntryIcon(extension); | 35 Profile* profile, |
36 BackgroundModeManager* background_mode_manager) | |
37 : applications_(new BackgroundApplicationListModel(profile)), | |
38 status_icon_(NULL), | |
39 context_menu_(NULL), | |
40 context_menu_application_offset_(0), | |
41 profile_(profile), | |
42 background_mode_manager_(background_mode_manager) { | |
36 } | 43 } |
37 | 44 |
38 void BackgroundModeManager::OnApplicationListChanged() { | 45 BackgroundModeManager::BackgroundModeData::~BackgroundModeData() { |
39 UpdateStatusTrayIconContextMenu(); | |
40 } | 46 } |
41 | 47 |
42 BackgroundModeManager::BackgroundModeManager(Profile* profile, | 48 /////////////////////////////////////////////////////////////////////////////// |
43 CommandLine* command_line) | 49 // BackgroundModeManager::BackgroundModeData, ui::SimpleMenuModel overrides |
44 : profile_(profile), | 50 bool BackgroundModeManager::BackgroundModeData::IsCommandIdChecked( |
45 applications_(profile), | 51 int command_id) const { |
52 DCHECK(command_id == IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND); | |
53 return true; | |
54 } | |
55 | |
56 bool BackgroundModeManager::BackgroundModeData::IsCommandIdEnabled( | |
57 int command_id) const { | |
58 // For now, we do not support disabled items. | |
59 return true; | |
60 } | |
61 | |
62 bool BackgroundModeManager::BackgroundModeData::GetAcceleratorForCommandId( | |
63 int command_id, ui::Accelerator* accelerator) { | |
64 // No accelerators for status icon context menus. | |
65 return false; | |
66 } | |
67 | |
68 void BackgroundModeManager::BackgroundModeData::ExecuteCommand(int item) { | |
69 switch (item) { | |
70 case IDC_ABOUT: | |
71 GetBrowserWindow()->OpenAboutChromeDialog(); | |
72 break; | |
73 case IDC_EXIT: | |
74 UserMetrics::RecordAction(UserMetricsAction("Exit")); | |
75 BrowserList::CloseAllBrowsersAndExit(); | |
76 break; | |
77 case IDC_OPTIONS: | |
78 GetBrowserWindow()->OpenOptionsDialog(); | |
79 break; | |
80 case IDC_TASK_MANAGER: | |
81 GetBrowserWindow()->OpenTaskManager(true); | |
82 break; | |
83 case IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND: { | |
84 // Background mode must already be enabled (as otherwise this menu would | |
85 // not be visible). | |
86 DCHECK(background_mode_manager_->IsBackgroundModePrefEnabled()); | |
87 DCHECK(BrowserList::WillKeepAlive()); | |
88 if (BrowserList::size() == 0) { | |
89 // There are no windows open - unchecking this will exit Chrome. Warn | |
90 // the user. | |
91 string16 tab_title = l10n_util::GetStringFUTF16(IDS_OPTIONS_TAB_TITLE, | |
92 l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE), | |
93 l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_TAB_LABEL)); | |
94 | |
95 if (!platform_util::SimpleYesNoBox( | |
96 NULL, | |
97 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), | |
98 l10n_util::GetStringFUTF16( | |
99 IDS_CONFIRM_EXIT_BACKGROUND_MODE_BODY, | |
100 tab_title))) { | |
101 return; | |
102 } | |
103 } | |
104 | |
105 // Set the background mode pref to "disabled" - the resulting notification | |
106 // will result in a call to DisableBackgroundMode(). | |
107 PrefService* service = g_browser_process->local_state(); | |
108 DCHECK(service); | |
109 service->SetBoolean(prefs::kBackgroundModeEnabled, false); | |
110 break; | |
111 } | |
112 default: | |
113 ExecuteApplication(item); | |
114 break; | |
115 } | |
116 } | |
117 | |
118 void BackgroundModeManager::BackgroundModeData::ExecuteApplication( | |
119 int item) { | |
120 Browser* browser = GetBrowserWindow(); | |
121 const Extension* extension = applications_->GetExtension(item); | |
122 browser->OpenApplicationTab(profile_, extension, NEW_FOREGROUND_TAB); | |
123 } | |
124 | |
125 Browser* BackgroundModeManager::BackgroundModeData::GetBrowserWindow() { | |
126 Browser* browser = BrowserList::GetLastActiveWithProfile(profile_); | |
127 if (!browser) { | |
128 Browser::OpenEmptyWindow(profile_); | |
129 browser = BrowserList::GetLastActiveWithProfile(profile_); | |
130 } | |
131 return browser; | |
132 } | |
133 | |
134 void BackgroundModeManager::BackgroundModeData::UpdateContextMenuEntryIcon( | |
135 const Extension* extension) { | |
136 if (!context_menu_) | |
137 return; | |
138 context_menu_->SetIcon( | |
139 context_menu_application_offset_ + | |
140 applications_->GetPosition(extension), | |
141 *(applications_->GetIcon(extension))); | |
142 | |
143 status_icon_->SetContextMenu(context_menu_); // for Update effect | |
144 } | |
145 | |
146 bool BackgroundModeManager::BackgroundModeData::HasBackgroundApp() { | |
147 return (applications_->size() > 0); | |
148 } | |
149 | |
150 /////////////////////////////////////////////////////////////////////////////// | |
151 // BackgroundModeManager, public | |
152 BackgroundModeManager::BackgroundModeManager(CommandLine* command_line) | |
153 : status_tray_(NULL), | |
46 background_app_count_(0), | 154 background_app_count_(0), |
47 context_menu_(NULL), | |
48 context_menu_application_offset_(0), | |
49 in_background_mode_(false), | 155 in_background_mode_(false), |
50 keep_alive_for_startup_(false), | 156 keep_alive_for_startup_(false) { |
51 status_tray_(NULL), | |
52 status_icon_(NULL) { | |
53 // If background mode is currently disabled, just exit - don't listen for any | 157 // If background mode is currently disabled, just exit - don't listen for any |
54 // notifications. | 158 // notifications. |
55 if (IsBackgroundModePermanentlyDisabled(command_line)) | 159 if (IsBackgroundModePermanentlyDisabled(command_line)) |
56 return; | 160 return; |
57 | 161 |
58 // Listen for the background mode preference changing. | 162 // Listen for the background mode preference changing. |
59 if (g_browser_process->local_state()) { // Skip for unit tests | 163 if (g_browser_process->local_state()) { // Skip for unit tests |
60 pref_registrar_.Init(g_browser_process->local_state()); | 164 pref_registrar_.Init(g_browser_process->local_state()); |
61 pref_registrar_.Add(prefs::kBackgroundModeEnabled, this); | 165 pref_registrar_.Add(prefs::kBackgroundModeEnabled, this); |
62 } | 166 } |
63 | 167 |
64 // Keep the browser alive until extensions are done loading - this is needed | 168 // Keep the browser alive until extensions are done loading - this is needed |
65 // by the --no-startup-window flag. We want to stay alive until we load | 169 // by the --no-startup-window flag. We want to stay alive until we load |
66 // extensions, at which point we should either run in background mode (if | 170 // extensions, at which point we should either run in background mode (if |
67 // there are background apps) or exit if there are none. | 171 // there are background apps) or exit if there are none. |
68 if (command_line->HasSwitch(switches::kNoStartupWindow)) { | 172 if (command_line->HasSwitch(switches::kNoStartupWindow)) { |
69 keep_alive_for_startup_ = true; | 173 keep_alive_for_startup_ = true; |
70 BrowserList::StartKeepAlive(); | 174 BrowserList::StartKeepAlive(); |
71 } | 175 } |
72 | 176 |
73 // If the -keep-alive-for-test flag is passed, then always keep chrome running | 177 // If the -keep-alive-for-test flag is passed, then always keep chrome running |
74 // in the background until the user explicitly terminates it, by acting as if | 178 // in the background until the user explicitly terminates it, by acting as if |
75 // we loaded a background app. | 179 // we loaded a background app. |
76 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKeepAliveForTest)) | 180 if (command_line->HasSwitch(switches::kKeepAliveForTest)) |
77 OnBackgroundAppLoaded(); | 181 OnBackgroundAppLoaded(); |
78 | 182 |
183 // Listen for the application shutting down so we can decrement our KeepAlive | |
184 // count. | |
185 registrar_.Add(this, NotificationType::APP_TERMINATING, | |
186 NotificationService::AllSources()); | |
187 } | |
188 | |
189 BackgroundModeManager::~BackgroundModeManager() { | |
190 for (std::map<Profile*, BackgroundModeInfo>::iterator it = | |
191 background_mode_data_.begin(); | |
192 it != background_mode_data_.end(); | |
193 ++it) { | |
194 it->second->applications_->RemoveObserver(this); | |
195 } | |
196 | |
197 // We're going away, so exit background mode (does nothing if we aren't in | |
198 // background mode currently). This is primarily needed for unit tests, | |
199 // because in an actual running system we'd get an APP_TERMINATING | |
200 // notification before being destroyed. | |
201 EndBackgroundMode(); | |
202 } | |
203 | |
204 // static | |
205 void BackgroundModeManager::RegisterPrefs(PrefService* prefs) { | |
206 prefs->RegisterBooleanPref(prefs::kUserCreatedLoginItem, false); | |
207 prefs->RegisterBooleanPref(prefs::kBackgroundModeEnabled, true); | |
208 } | |
209 | |
210 | |
211 void BackgroundModeManager::RegisterProfile(Profile* profile) { | |
212 // We don't want to register multiple times for one profile. | |
213 DCHECK(background_mode_data_.find(profile) == background_mode_data_.end()); | |
214 BackgroundModeInfo bmd(new BackgroundModeData(profile, this)); | |
215 background_mode_data_[profile] = bmd; | |
216 | |
79 // Listen for when extensions are loaded/unloaded so we can track the | 217 // Listen for when extensions are loaded/unloaded so we can track the |
80 // number of background apps and modify our keep-alive and launch-on-startup | 218 // number of background apps and modify our keep-alive and launch-on-startup |
81 // state appropriately. | 219 // state appropriately. |
82 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | 220 registrar_.Add(this, NotificationType::EXTENSION_LOADED, |
83 Source<Profile>(profile)); | 221 Source<Profile>(profile)); |
84 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | 222 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, |
85 Source<Profile>(profile)); | 223 Source<Profile>(profile)); |
86 | 224 |
87 // Check for the presence of background apps after all extensions have been | 225 // Check for the presence of background apps after all extensions have been |
88 // loaded, to handle the case where an extension has been manually removed | 226 // loaded, to handle the case where an extension has been manually removed |
89 // while Chrome was not running. | 227 // while Chrome was not running. |
90 registrar_.Add(this, NotificationType::EXTENSIONS_READY, | 228 registrar_.Add(this, NotificationType::EXTENSIONS_READY, |
91 Source<Profile>(profile)); | 229 Source<Profile>(profile)); |
92 | 230 |
93 // Listen for the application shutting down so we can decrement our KeepAlive | 231 background_mode_data_[profile]->applications_->AddObserver(this); |
Andrew T Wilson (Slow)
2011/05/23 20:35:40
So, it looks like we mostly just delegate the hand
rpetterson
2011/05/24 02:18:00
Yes, it will be useful in the future. Currently th
| |
94 // count. | |
95 registrar_.Add(this, NotificationType::APP_TERMINATING, | |
96 NotificationService::AllSources()); | |
97 | |
98 applications_.AddObserver(this); | |
99 } | 232 } |
100 | 233 |
101 BackgroundModeManager::~BackgroundModeManager() { | 234 /////////////////////////////////////////////////////////////////////////////// |
102 applications_.RemoveObserver(this); | 235 // BackgroundModeManager, NotificationObserver overrides |
103 | |
104 // We're going away, so exit background mode (does nothing if we aren't in | |
105 // background mode currently). This is primarily needed for unit tests, | |
106 // because in an actual running system we'd get an APP_TERMINATING | |
107 // notification before being destroyed. | |
108 EndBackgroundMode(); | |
109 } | |
110 | |
111 void BackgroundModeManager::Observe(NotificationType type, | 236 void BackgroundModeManager::Observe(NotificationType type, |
112 const NotificationSource& source, | 237 const NotificationSource& source, |
113 const NotificationDetails& details) { | 238 const NotificationDetails& details) { |
114 switch (type.value) { | 239 switch (type.value) { |
115 case NotificationType::PREF_CHANGED: | 240 case NotificationType::PREF_CHANGED: |
116 DCHECK(*Details<std::string>(details).ptr() == | 241 DCHECK(*Details<std::string>(details).ptr() == |
117 prefs::kBackgroundModeEnabled); | 242 prefs::kBackgroundModeEnabled); |
118 if (IsBackgroundModePrefEnabled()) | 243 if (IsBackgroundModePrefEnabled()) |
119 EnableBackgroundMode(); | 244 EnableBackgroundMode(); |
120 else | 245 else |
(...skipping 12 matching lines...) Expand all Loading... | |
133 // launch on startup even after the user removes the LoginItem manually. | 258 // launch on startup even after the user removes the LoginItem manually. |
134 #if !defined(OS_MACOSX) | 259 #if !defined(OS_MACOSX) |
135 EnableLaunchOnStartup(background_app_count_ > 0); | 260 EnableLaunchOnStartup(background_app_count_ > 0); |
136 #endif | 261 #endif |
137 break; | 262 break; |
138 case NotificationType::EXTENSION_LOADED: { | 263 case NotificationType::EXTENSION_LOADED: { |
139 Extension* extension = Details<Extension>(details).ptr(); | 264 Extension* extension = Details<Extension>(details).ptr(); |
140 if (BackgroundApplicationListModel::IsBackgroundApp(*extension)) { | 265 if (BackgroundApplicationListModel::IsBackgroundApp(*extension)) { |
141 // Extensions loaded after the ExtensionsService is ready should be | 266 // Extensions loaded after the ExtensionsService is ready should be |
142 // treated as new installs. | 267 // treated as new installs. |
143 if (profile_->GetExtensionService()->is_ready()) | 268 |
Andrew T Wilson (Slow)
2011/05/23 20:35:40
Remove extra blank line
rpetterson
2011/05/24 02:18:00
Done.
| |
144 OnBackgroundAppInstalled(extension); | 269 Profile* profile = Source<Profile>(source).ptr(); |
270 if (profile->GetExtensionService()->is_ready()) | |
271 OnBackgroundAppInstalled(extension, profile); | |
145 OnBackgroundAppLoaded(); | 272 OnBackgroundAppLoaded(); |
146 } | 273 } |
147 } | 274 } |
148 break; | 275 break; |
149 case NotificationType::EXTENSION_UNLOADED: | 276 case NotificationType::EXTENSION_UNLOADED: |
150 if (BackgroundApplicationListModel::IsBackgroundApp( | 277 if (BackgroundApplicationListModel::IsBackgroundApp( |
151 *Details<UnloadedExtensionInfo>(details)->extension)) { | 278 *Details<UnloadedExtensionInfo>(details)->extension)) { |
152 Details<UnloadedExtensionInfo> info = | 279 Details<UnloadedExtensionInfo> info = |
153 Details<UnloadedExtensionInfo>(details); | 280 Details<UnloadedExtensionInfo>(details); |
154 // If we already got an unload notification when it was disabled, ignore | 281 // If we already got an unload notification when it was disabled, ignore |
155 // this one. | 282 // this one. |
156 // TODO(atwilson): Change BackgroundModeManager to use | 283 // TODO(atwilson): Change BackgroundModeManager to use |
157 // BackgroundApplicationListModel instead of tracking the count here. | 284 // BackgroundApplicationListModel instead of tracking the count here. |
158 if (info->already_disabled) | 285 if (info->already_disabled) |
159 return; | 286 return; |
160 OnBackgroundAppUnloaded(); | 287 OnBackgroundAppUnloaded(); |
161 OnBackgroundAppUninstalled(); | 288 Profile* profile = Source<Profile>(source).ptr(); |
289 OnBackgroundAppUninstalled(profile); | |
162 } | 290 } |
163 break; | 291 break; |
164 case NotificationType::APP_TERMINATING: | 292 case NotificationType::APP_TERMINATING: |
165 // Make sure we aren't still keeping the app alive (only happens if we | 293 // Make sure we aren't still keeping the app alive (only happens if we |
166 // don't receive an EXTENSIONS_READY notification for some reason). | 294 // don't receive an EXTENSIONS_READY notification for some reason). |
167 EndKeepAliveForStartup(); | 295 EndKeepAliveForStartup(); |
168 // Performing an explicit shutdown, so exit background mode (does nothing | 296 // Performing an explicit shutdown, so exit background mode (does nothing |
169 // if we aren't in background mode currently). | 297 // if we aren't in background mode currently). |
170 EndBackgroundMode(); | 298 EndBackgroundMode(); |
171 // Shutting down, so don't listen for any more notifications so we don't | 299 // Shutting down, so don't listen for any more notifications so we don't |
172 // try to re-enter/exit background mode again. | 300 // try to re-enter/exit background mode again. |
173 registrar_.RemoveAll(); | 301 registrar_.RemoveAll(); |
174 break; | 302 break; |
175 default: | 303 default: |
176 NOTREACHED(); | 304 NOTREACHED(); |
177 break; | 305 break; |
178 } | 306 } |
179 } | 307 } |
180 | 308 |
309 /////////////////////////////////////////////////////////////////////////////// | |
310 // BackgroundModeManager, BackgroundApplicationLisModel::Observer overrides | |
Andrew T Wilson (Slow)
2011/05/23 20:35:40
Nit: LisModel->ListModel
rpetterson
2011/05/24 02:18:00
Done.
| |
311 void BackgroundModeManager::OnApplicationDataChanged( | |
312 const Extension* extension, Profile* profile) { | |
313 UpdateContextMenuEntryIcon(extension, profile); | |
314 } | |
315 | |
316 void BackgroundModeManager::OnApplicationListChanged(Profile* profile) { | |
317 UpdateStatusTrayIconContextMenu(profile); | |
318 } | |
319 | |
320 | |
321 /////////////////////////////////////////////////////////////////////////////// | |
322 // BackgroundModeManager, private | |
181 void BackgroundModeManager::EndKeepAliveForStartup() { | 323 void BackgroundModeManager::EndKeepAliveForStartup() { |
182 if (keep_alive_for_startup_) { | 324 if (keep_alive_for_startup_) { |
183 keep_alive_for_startup_ = false; | 325 keep_alive_for_startup_ = false; |
184 // We call this via the message queue to make sure we don't try to end | 326 // We call this via the message queue to make sure we don't try to end |
185 // keep-alive (which can shutdown Chrome) before the message loop has | 327 // keep-alive (which can shutdown Chrome) before the message loop has |
186 // started. | 328 // started. |
187 MessageLoop::current()->PostTask( | 329 MessageLoop::current()->PostTask( |
188 FROM_HERE, NewRunnableFunction(BrowserList::EndKeepAlive)); | 330 FROM_HERE, NewRunnableFunction(BrowserList::EndKeepAlive)); |
189 } | 331 } |
190 } | 332 } |
191 | 333 |
192 void BackgroundModeManager::OnBackgroundAppLoaded() { | 334 void BackgroundModeManager::OnBackgroundAppLoaded() { |
193 // When a background app loads, increment our count and also enable | 335 // When a background app loads, increment our count and also enable |
194 // KeepAlive mode if the preference is set. | 336 // KeepAlive mode if the preference is set. |
337 // The count here is across all profiles since we must have background | |
338 // mode if there is even one. | |
195 background_app_count_++; | 339 background_app_count_++; |
196 if (background_app_count_ == 1) | 340 if (background_app_count_ == 1) |
197 StartBackgroundMode(); | 341 StartBackgroundMode(); |
198 } | 342 } |
199 | 343 |
200 void BackgroundModeManager::StartBackgroundMode() { | 344 void BackgroundModeManager::StartBackgroundMode() { |
201 // Don't bother putting ourselves in background mode if we're already there | 345 // Don't bother putting ourselves in background mode if we're already there |
202 // or if background mode is disabled. | 346 // or if background mode is disabled. |
203 if (in_background_mode_ || !IsBackgroundModePrefEnabled()) | 347 if (in_background_mode_ || !IsBackgroundModePrefEnabled()) |
204 return; | 348 return; |
205 | 349 |
206 // Mark ourselves as running in background mode. | 350 // Mark ourselves as running in background mode. |
207 in_background_mode_ = true; | 351 in_background_mode_ = true; |
208 | 352 |
209 // Put ourselves in KeepAlive mode and create a status tray icon. | 353 // Put ourselves in KeepAlive mode and create a status tray icon. |
210 BrowserList::StartKeepAlive(); | 354 BrowserList::StartKeepAlive(); |
211 | 355 |
212 // Display a status icon to exit Chrome. | 356 // Display a status icon to exit Chrome. |
213 CreateStatusTrayIcon(); | 357 InitStatusTrayIcons(); |
358 } | |
359 | |
360 void BackgroundModeManager::InitStatusTrayIcons() { | |
361 // Only initialize status tray icons for those profiles which actually | |
362 // have a background app running. | |
363 for (std::map<Profile*, BackgroundModeInfo>::iterator it = | |
364 background_mode_data_.begin(); | |
365 it != background_mode_data_.end(); | |
366 ++it) { | |
367 if (it->second->HasBackgroundApp()) { | |
Andrew T Wilson (Slow)
2011/05/23 20:35:40
nit: Probably should remove curly braces since the
rpetterson
2011/05/24 02:18:00
Done.
| |
368 CreateStatusTrayIcon(it->first); | |
369 } | |
370 } | |
214 } | 371 } |
215 | 372 |
216 void BackgroundModeManager::OnBackgroundAppUnloaded() { | 373 void BackgroundModeManager::OnBackgroundAppUnloaded() { |
217 // When a background app unloads, decrement our count and also end | 374 // When a background app unloads, decrement our count and also end |
218 // KeepAlive mode if appropriate. | 375 // KeepAlive mode if appropriate. |
219 background_app_count_--; | 376 background_app_count_--; |
220 DCHECK_GE(background_app_count_, 0); | 377 DCHECK_GE(background_app_count_, 0); |
221 if (background_app_count_ == 0) | 378 if (background_app_count_ == 0) |
222 EndBackgroundMode(); | 379 EndBackgroundMode(); |
223 } | 380 } |
224 | 381 |
225 void BackgroundModeManager::EndBackgroundMode() { | 382 void BackgroundModeManager::EndBackgroundMode() { |
226 if (!in_background_mode_) | 383 if (!in_background_mode_) |
227 return; | 384 return; |
228 in_background_mode_ = false; | 385 in_background_mode_ = false; |
229 | 386 |
230 // End KeepAlive mode and blow away our status tray icon. | 387 // End KeepAlive mode and blow away our status tray icon. |
231 BrowserList::EndKeepAlive(); | 388 BrowserList::EndKeepAlive(); |
232 RemoveStatusTrayIcon(); | 389 // There is a status tray icon for each profile. Blow them all away. |
390 for (std::map<Profile*, BackgroundModeInfo>::iterator it = | |
391 background_mode_data_.begin(); | |
392 it != background_mode_data_.end(); | |
393 ++it) { | |
394 RemoveStatusTrayIcon(it->first); | |
395 } | |
233 } | 396 } |
234 | 397 |
235 void BackgroundModeManager::EnableBackgroundMode() { | 398 void BackgroundModeManager::EnableBackgroundMode() { |
236 DCHECK(IsBackgroundModePrefEnabled()); | 399 DCHECK(IsBackgroundModePrefEnabled()); |
237 // If background mode should be enabled, but isn't, turn it on. | 400 // If background mode should be enabled, but isn't, turn it on. |
238 if (background_app_count_ > 0 && !in_background_mode_) { | 401 if (background_app_count_ > 0 && !in_background_mode_) { |
239 StartBackgroundMode(); | 402 StartBackgroundMode(); |
240 EnableLaunchOnStartup(true); | 403 EnableLaunchOnStartup(true); |
241 } | 404 } |
242 } | 405 } |
243 | 406 |
244 void BackgroundModeManager::DisableBackgroundMode() { | 407 void BackgroundModeManager::DisableBackgroundMode() { |
245 DCHECK(!IsBackgroundModePrefEnabled()); | 408 DCHECK(!IsBackgroundModePrefEnabled()); |
246 // If background mode is currently enabled, turn it off. | 409 // If background mode is currently enabled, turn it off. |
247 if (in_background_mode_) { | 410 if (in_background_mode_) { |
248 EndBackgroundMode(); | 411 EndBackgroundMode(); |
249 EnableLaunchOnStartup(false); | 412 EnableLaunchOnStartup(false); |
250 } | 413 } |
251 } | 414 } |
252 | 415 |
253 void BackgroundModeManager::OnBackgroundAppInstalled( | 416 void BackgroundModeManager::OnBackgroundAppInstalled( |
254 const Extension* extension) { | 417 const Extension* extension, Profile* profile) { |
255 // Background mode is disabled - don't do anything. | 418 // Background mode is disabled - don't do anything. |
256 if (!IsBackgroundModePrefEnabled()) | 419 if (!IsBackgroundModePrefEnabled()) |
257 return; | 420 return; |
258 | 421 |
259 // We're installing a background app. If this is the first background app | 422 // We're installing a background app. If this is the first background app |
260 // being installed, make sure we are set to launch on startup. | 423 // being installed, make sure we are set to launch on startup. |
261 if (background_app_count_ == 0) | 424 if (background_app_count_ == 0) |
262 EnableLaunchOnStartup(true); | 425 EnableLaunchOnStartup(true); |
263 | 426 |
427 // Check if we need a status tray icon and make one if we do. | |
428 CreateStatusTrayIcon(profile); | |
429 | |
264 // Notify the user that a background app has been installed. | 430 // Notify the user that a background app has been installed. |
265 if (extension) // NULL when called by unit tests. | 431 if (extension) // NULL when called by unit tests. |
266 DisplayAppInstalledNotification(extension); | 432 DisplayAppInstalledNotification(extension, profile); |
267 } | 433 } |
268 | 434 |
269 void BackgroundModeManager::OnBackgroundAppUninstalled() { | 435 void BackgroundModeManager::OnBackgroundAppUninstalled(Profile* profile) { |
436 // Check if we need to remove the status tray icon if there are no | |
437 // more background apps. | |
438 BackgroundModeInfo bmd = GetBackgroundModeInfo(profile); | |
439 DCHECK(bmd.get()); | |
440 // If there are still background apps for this profile, don't remove | |
441 // the status tray icon. | |
442 if (!bmd->HasBackgroundApp()) | |
443 RemoveStatusTrayIcon(profile); | |
444 | |
270 // When uninstalling a background app, disable launch on startup if | 445 // When uninstalling a background app, disable launch on startup if |
271 // we have no more background apps. | 446 // we have no more background apps. |
272 if (background_app_count_ == 0) | 447 if (background_app_count_ == 0) |
273 EnableLaunchOnStartup(false); | 448 EnableLaunchOnStartup(false); |
274 } | 449 } |
275 | 450 |
276 void BackgroundModeManager::CreateStatusTrayIcon() { | 451 void BackgroundModeManager::CreateStatusTrayIcon(Profile* profile) { |
277 // Only need status icons on windows/linux. ChromeOS doesn't allow exiting | 452 // Only need status icons on windows/linux. ChromeOS doesn't allow exiting |
278 // Chrome and Mac can use the dock icon instead. | 453 // Chrome and Mac can use the dock icon instead. |
454 | |
455 // Since there are multiple profiles which share the status tray, we now | |
456 // use the browser process to keep track of it. | |
279 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) | 457 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) |
280 if (!status_tray_) | 458 if (!status_tray_) |
281 status_tray_ = profile_->GetStatusTray(); | 459 status_tray_ = g_browser_process->status_tray(); |
282 #endif | 460 #endif |
283 | 461 |
284 // If the platform doesn't support status icons, or we've already created | 462 // If the platform doesn't support status icons, or we've already created |
285 // our status icon, just return. | 463 // our status icon, just return. |
286 if (!status_tray_ || status_icon_) | 464 BackgroundModeInfo bmd = GetBackgroundModeInfo(profile); |
287 return; | 465 if (!status_tray_ || bmd->status_icon_) |
288 status_icon_ = status_tray_->CreateStatusIcon(); | |
289 if (!status_icon_) | |
290 return; | 466 return; |
291 | 467 |
292 // Set the image and add ourselves as a click observer on it | 468 bmd->status_icon_ = status_tray_->CreateStatusIcon(); |
469 if (!bmd->status_icon_) | |
470 return; | |
471 | |
472 // Set the image and add ourselves as a click observer on it. | |
473 // TODO(rlp): Status tray icon should have submenus for each profile. | |
293 SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed( | 474 SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed( |
294 IDR_STATUS_TRAY_ICON); | 475 IDR_STATUS_TRAY_ICON); |
295 status_icon_->SetImage(*bitmap); | 476 bmd->status_icon_->SetImage(*bitmap); |
296 status_icon_->SetToolTip(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); | 477 bmd->status_icon_->SetToolTip(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); |
297 UpdateStatusTrayIconContextMenu(); | 478 UpdateStatusTrayIconContextMenu(profile); |
298 } | 479 } |
299 | 480 |
300 void BackgroundModeManager::UpdateContextMenuEntryIcon( | 481 void BackgroundModeManager::UpdateContextMenuEntryIcon( |
301 const Extension* extension) { | 482 const Extension* extension, Profile* profile) { |
302 if (!context_menu_) | 483 BackgroundModeInfo bmd = GetBackgroundModeInfo(profile); |
303 return; | 484 DCHECK(bmd.get()); |
304 context_menu_->SetIcon( | 485 bmd->UpdateContextMenuEntryIcon(extension); |
305 context_menu_application_offset_ + applications_.GetPosition(extension), | |
306 *(applications_.GetIcon(extension))); | |
307 status_icon_->SetContextMenu(context_menu_); // for Update effect | |
308 } | 486 } |
309 | 487 |
310 void BackgroundModeManager::UpdateStatusTrayIconContextMenu() { | 488 void BackgroundModeManager::UpdateStatusTrayIconContextMenu(Profile* profile) { |
311 if (!status_icon_) | 489 BackgroundModeInfo bmd = GetBackgroundModeInfo(profile); |
312 return; | 490 DCHECK(bmd.get()); |
491 if (!bmd->status_icon_) { | |
492 // If no status icon exists, it's either because one wasn't created when | |
493 // it should have been which can happen when extensions load after the | |
494 // profile has already been registered with the background mode manager. | |
495 // The other case is if we aren't in background mode. | |
496 if (in_background_mode_) | |
497 CreateStatusTrayIcon(profile); | |
498 else | |
499 return; | |
500 } | |
313 | 501 |
502 // TODO(rlp): Add current profile color. | |
314 // Create a context menu item for Chrome. | 503 // Create a context menu item for Chrome. |
315 ui::SimpleMenuModel* menu = new ui::SimpleMenuModel(this); | 504 ui::SimpleMenuModel* menu = new ui::SimpleMenuModel(bmd.get()); |
316 // Add About item | 505 // Add About item |
317 menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT, | 506 menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT, |
318 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); | 507 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); |
319 menu->AddItem(IDC_OPTIONS, GetPreferencesMenuLabel()); | 508 menu->AddItem(IDC_OPTIONS, GetPreferencesMenuLabel()); |
320 menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); | 509 menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); |
321 menu->AddSeparator(); | 510 menu->AddSeparator(); |
322 int position = 0; | 511 int position = 0; |
323 context_menu_application_offset_ = menu->GetItemCount(); | 512 bmd->context_menu_application_offset_ = menu->GetItemCount(); |
324 for (ExtensionList::const_iterator cursor = applications_.begin(); | 513 for (ExtensionList::const_iterator cursor = bmd->applications_->begin(); |
325 cursor != applications_.end(); | 514 cursor != bmd->applications_->end(); |
326 ++cursor, ++position) { | 515 ++cursor, ++position) { |
327 const SkBitmap* icon = applications_.GetIcon(*cursor); | 516 const SkBitmap* icon = bmd->applications_->GetIcon(*cursor); |
328 DCHECK(position == applications_.GetPosition(*cursor)); | 517 DCHECK(position == bmd->applications_->GetPosition(*cursor)); |
329 const std::string& name = (*cursor)->name(); | 518 const std::string& name = (*cursor)->name(); |
330 menu->AddItem(position, UTF8ToUTF16(name)); | 519 menu->AddItem(position, UTF8ToUTF16(name)); |
331 if (icon) | 520 if (icon) |
332 menu->SetIcon(menu->GetItemCount() - 1, *icon); | 521 menu->SetIcon(menu->GetItemCount() - 1, *icon); |
333 } | 522 } |
334 if (applications_.size() > 0) | 523 if (bmd->applications_->size() > 0) |
335 menu->AddSeparator(); | 524 menu->AddSeparator(); |
336 menu->AddCheckItemWithStringId( | 525 menu->AddCheckItemWithStringId( |
337 IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND, | 526 IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND, |
338 IDS_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND); | 527 IDS_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND); |
339 menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT); | 528 menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT); |
340 context_menu_ = menu; | 529 bmd->context_menu_ = menu; |
341 status_icon_->SetContextMenu(menu); | 530 bmd->status_icon_->SetContextMenu(menu); |
342 } | 531 } |
343 | 532 |
344 bool BackgroundModeManager::IsCommandIdChecked(int command_id) const { | 533 void BackgroundModeManager::RemoveStatusTrayIcon(Profile* profile) { |
345 DCHECK(command_id == IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND); | 534 BackgroundModeInfo bmd = GetBackgroundModeInfo(profile); |
Andrew T Wilson (Slow)
2011/05/23 20:35:40
If we were going to keep the multiple-status-icon
rpetterson
2011/05/24 02:18:00
This was my thought exactly. I was going to move i
| |
346 return true; | 535 DCHECK(bmd.get()); |
536 | |
537 if (bmd->status_icon_) | |
538 status_tray_->RemoveStatusIcon(bmd->status_icon_); | |
539 bmd->status_icon_ = NULL; | |
540 bmd->context_menu_ = NULL; // Do not delete, points within |status_icon_|. | |
347 } | 541 } |
348 | 542 |
349 bool BackgroundModeManager::IsCommandIdEnabled(int command_id) const { | 543 BackgroundModeManager::BackgroundModeInfo |
350 // For now, we do not support disabled items. | 544 BackgroundModeManager::GetBackgroundModeInfo(Profile* profile) { |
Andrew T Wilson (Slow)
2011/05/23 20:35:40
nit: this is one of the few cases where you should
rpetterson
2011/05/24 02:18:00
Done.
| |
351 return true; | 545 DCHECK(background_mode_data_.find(profile) != background_mode_data_.end()); |
352 } | 546 return background_mode_data_[profile]; |
353 | |
354 bool BackgroundModeManager::GetAcceleratorForCommandId( | |
355 int command_id, | |
356 ui::Accelerator* accelerator) { | |
357 // No accelerators for status icon context menus. | |
358 return false; | |
359 } | |
360 | |
361 void BackgroundModeManager::RemoveStatusTrayIcon() { | |
362 if (status_icon_) | |
363 status_tray_->RemoveStatusIcon(status_icon_); | |
364 status_icon_ = NULL; | |
365 context_menu_ = NULL; // Do not delete, points within |status_icon_|. | |
366 } | |
367 | |
368 void BackgroundModeManager::ExecuteApplication(int item) { | |
369 DCHECK(item >= 0 && item < static_cast<int>(applications_.size())); | |
370 Browser* browser = BrowserList::GetLastActive(); | |
371 if (!browser) { | |
372 Browser::OpenEmptyWindow(profile_); | |
373 browser = BrowserList::GetLastActive(); | |
374 } | |
375 const Extension* extension = applications_.GetExtension(item); | |
376 browser->OpenApplicationTab(profile_, extension, NEW_FOREGROUND_TAB); | |
377 } | |
378 | |
379 void BackgroundModeManager::ExecuteCommand(int item) { | |
380 switch (item) { | |
381 case IDC_ABOUT: | |
382 GetBrowserWindow()->OpenAboutChromeDialog(); | |
383 break; | |
384 case IDC_EXIT: | |
385 UserMetrics::RecordAction(UserMetricsAction("Exit")); | |
386 BrowserList::CloseAllBrowsersAndExit(); | |
387 break; | |
388 case IDC_OPTIONS: | |
389 GetBrowserWindow()->OpenOptionsDialog(); | |
390 break; | |
391 case IDC_TASK_MANAGER: | |
392 GetBrowserWindow()->OpenTaskManager(true); | |
393 break; | |
394 case IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND: { | |
395 // Background mode must already be enabled (as otherwise this menu would | |
396 // not be visible). | |
397 DCHECK(IsBackgroundModePrefEnabled()); | |
398 DCHECK(BrowserList::WillKeepAlive()); | |
399 if (BrowserList::size() == 0) { | |
400 // There are no windows open - unchecking this will exit Chrome. Warn | |
401 // the user. | |
402 string16 tab_title = l10n_util::GetStringFUTF16(IDS_OPTIONS_TAB_TITLE, | |
403 l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE), | |
404 l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_TAB_LABEL)); | |
405 | |
406 if (!platform_util::SimpleYesNoBox( | |
407 NULL, | |
408 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), | |
409 l10n_util::GetStringFUTF16( | |
410 IDS_CONFIRM_EXIT_BACKGROUND_MODE_BODY, | |
411 tab_title))) { | |
412 return; | |
413 } | |
414 } | |
415 | |
416 // Set the background mode pref to "disabled" - the resulting notification | |
417 // will result in a call to DisableBackgroundMode(). | |
418 PrefService* service = g_browser_process->local_state(); | |
419 DCHECK(service); | |
420 service->SetBoolean(prefs::kBackgroundModeEnabled, false); | |
421 break; | |
422 } | |
423 default: | |
424 ExecuteApplication(item); | |
425 break; | |
426 } | |
427 } | |
428 | |
429 Browser* BackgroundModeManager::GetBrowserWindow() { | |
430 Browser* browser = BrowserList::GetLastActive(); | |
431 if (!browser) { | |
432 Browser::OpenEmptyWindow(profile_); | |
433 browser = BrowserList::GetLastActive(); | |
434 } | |
435 return browser; | |
436 } | 547 } |
437 | 548 |
438 // static | 549 // static |
439 bool BackgroundModeManager::IsBackgroundModePermanentlyDisabled( | 550 bool BackgroundModeManager::IsBackgroundModePermanentlyDisabled( |
440 const CommandLine* command_line) { | 551 const CommandLine* command_line) { |
441 | 552 |
442 // Background mode is disabled if the appropriate flag is passed, or if | 553 // Background mode is disabled if the appropriate flag is passed, or if |
443 // extensions are disabled, or if the associated preference is unset. It's | 554 // extensions are disabled, or if the associated preference is unset. It's |
444 // always disabled on chromeos since chrome is always running on that | 555 // always disabled on chromeos since chrome is always running on that |
445 // platform, making it superfluous. | 556 // platform, making it superfluous. |
446 #if defined(OS_CHROMEOS) | 557 #if defined(OS_CHROMEOS) |
447 return true; | 558 return true; |
448 #else | 559 #else |
449 bool background_mode_disabled = | 560 bool background_mode_disabled = |
450 command_line->HasSwitch(switches::kDisableBackgroundMode) || | 561 command_line->HasSwitch(switches::kDisableBackgroundMode) || |
451 command_line->HasSwitch(switches::kDisableExtensions); | 562 command_line->HasSwitch(switches::kDisableExtensions); |
452 return background_mode_disabled; | 563 return background_mode_disabled; |
453 #endif | 564 #endif |
454 } | 565 } |
455 | 566 |
456 bool BackgroundModeManager::IsBackgroundModePrefEnabled() { | 567 bool BackgroundModeManager::IsBackgroundModePrefEnabled() { |
457 PrefService* service = g_browser_process->local_state(); | 568 PrefService* service = g_browser_process->local_state(); |
458 DCHECK(service); | 569 DCHECK(service); |
459 return service->GetBoolean(prefs::kBackgroundModeEnabled); | 570 return service->GetBoolean(prefs::kBackgroundModeEnabled); |
460 } | 571 } |
461 | |
462 // static | |
463 void BackgroundModeManager::RegisterPrefs(PrefService* prefs) { | |
464 prefs->RegisterBooleanPref(prefs::kUserCreatedLoginItem, false); | |
465 prefs->RegisterBooleanPref(prefs::kBackgroundModeEnabled, true); | |
466 } | |
OLD | NEW |