Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: chrome/browser/background_mode_manager.cc

Issue 6914021: Modifying the BackgroundModeManager to handle multiple profiles. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698