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