OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/background/background_contents_service.h" | 5 #include "chrome/browser/background/background_contents_service.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 // uninstalls the extension. | 209 // uninstalls the extension. |
210 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, | 210 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, |
211 content::Source<Profile>(profile)); | 211 content::Source<Profile>(profile)); |
212 } | 212 } |
213 | 213 |
214 void BackgroundContentsService::Observe( | 214 void BackgroundContentsService::Observe( |
215 int type, | 215 int type, |
216 const content::NotificationSource& source, | 216 const content::NotificationSource& source, |
217 const content::NotificationDetails& details) { | 217 const content::NotificationDetails& details) { |
218 switch (type) { | 218 switch (type) { |
219 case chrome::NOTIFICATION_EXTENSIONS_READY: | 219 case chrome::NOTIFICATION_EXTENSIONS_READY: { |
220 LoadBackgroundContentsFromManifests( | 220 Profile* profile = content::Source<Profile>(source).ptr(); |
221 content::Source<Profile>(source).ptr()); | 221 LoadBackgroundContentsFromManifests(profile); |
222 LoadBackgroundContentsFromPrefs(content::Source<Profile>(source).ptr()); | 222 LoadBackgroundContentsFromPrefs(profile); |
| 223 SendChangeNotification(profile); |
223 break; | 224 break; |
| 225 } |
224 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: | 226 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: |
225 BackgroundContentsShutdown( | 227 BackgroundContentsShutdown( |
226 content::Details<BackgroundContents>(details).ptr()); | 228 content::Details<BackgroundContents>(details).ptr()); |
| 229 SendChangeNotification(content::Source<Profile>(source).ptr()); |
227 break; | 230 break; |
228 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_CLOSED: | 231 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_CLOSED: |
229 DCHECK(IsTracked(content::Details<BackgroundContents>(details).ptr())); | 232 DCHECK(IsTracked(content::Details<BackgroundContents>(details).ptr())); |
230 UnregisterBackgroundContents( | 233 UnregisterBackgroundContents( |
231 content::Details<BackgroundContents>(details).ptr()); | 234 content::Details<BackgroundContents>(details).ptr()); |
| 235 // CLOSED is always followed by a DELETED notification so we'll send our |
| 236 // change notification there. |
232 break; | 237 break; |
233 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: { | 238 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: { |
234 DCHECK(IsTracked(content::Details<BackgroundContents>(details).ptr())); | 239 DCHECK(IsTracked(content::Details<BackgroundContents>(details).ptr())); |
235 | 240 |
236 // Do not register in the pref if the extension has a manifest-specified | 241 // Do not register in the pref if the extension has a manifest-specified |
237 // background page. | 242 // background page. |
238 BackgroundContents* bgcontents = | 243 BackgroundContents* bgcontents = |
239 content::Details<BackgroundContents>(details).ptr(); | 244 content::Details<BackgroundContents>(details).ptr(); |
240 Profile* profile = content::Source<Profile>(source).ptr(); | 245 Profile* profile = content::Source<Profile>(source).ptr(); |
241 const string16& appid = GetParentApplicationId(bgcontents); | 246 const string16& appid = GetParentApplicationId(bgcontents); |
(...skipping 23 matching lines...) Expand all Loading... |
265 // Now load the manifest-specified background page. If service isn't | 270 // Now load the manifest-specified background page. If service isn't |
266 // ready, then the background page will be loaded from the | 271 // ready, then the background page will be loaded from the |
267 // EXTENSIONS_READY callback. | 272 // EXTENSIONS_READY callback. |
268 LoadBackgroundContents(profile, extension->GetBackgroundURL(), | 273 LoadBackgroundContents(profile, extension->GetBackgroundURL(), |
269 ASCIIToUTF16("background"), UTF8ToUTF16(extension->id())); | 274 ASCIIToUTF16("background"), UTF8ToUTF16(extension->id())); |
270 } | 275 } |
271 } | 276 } |
272 | 277 |
273 // Remove any "This extension has crashed" balloons. | 278 // Remove any "This extension has crashed" balloons. |
274 ScheduleCloseBalloon(extension->id()); | 279 ScheduleCloseBalloon(extension->id()); |
| 280 SendChangeNotification(profile); |
275 break; | 281 break; |
276 } | 282 } |
277 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: | 283 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: |
278 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED: { | 284 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED: { |
279 Profile* profile = content::Source<Profile>(source).ptr(); | 285 Profile* profile = content::Source<Profile>(source).ptr(); |
280 const Extension* extension = NULL; | 286 const Extension* extension = NULL; |
281 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED) { | 287 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED) { |
282 BackgroundContents* bg = | 288 BackgroundContents* bg = |
283 content::Details<BackgroundContents>(details).ptr(); | 289 content::Details<BackgroundContents>(details).ptr(); |
284 std::string extension_id = UTF16ToASCII( | 290 std::string extension_id = UTF16ToASCII( |
(...skipping 19 matching lines...) Expand all Loading... |
304 break; | 310 break; |
305 } | 311 } |
306 case chrome::NOTIFICATION_EXTENSION_UNLOADED: | 312 case chrome::NOTIFICATION_EXTENSION_UNLOADED: |
307 switch (content::Details<UnloadedExtensionInfo>(details)->reason) { | 313 switch (content::Details<UnloadedExtensionInfo>(details)->reason) { |
308 case extension_misc::UNLOAD_REASON_DISABLE: // Fall through. | 314 case extension_misc::UNLOAD_REASON_DISABLE: // Fall through. |
309 case extension_misc::UNLOAD_REASON_TERMINATE: // Fall through. | 315 case extension_misc::UNLOAD_REASON_TERMINATE: // Fall through. |
310 case extension_misc::UNLOAD_REASON_UNINSTALL: | 316 case extension_misc::UNLOAD_REASON_UNINSTALL: |
311 ShutdownAssociatedBackgroundContents( | 317 ShutdownAssociatedBackgroundContents( |
312 ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)-> | 318 ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)-> |
313 extension->id())); | 319 extension->id())); |
| 320 SendChangeNotification(content::Source<Profile>(source).ptr()); |
314 break; | 321 break; |
315 case extension_misc::UNLOAD_REASON_UPDATE: { | 322 case extension_misc::UNLOAD_REASON_UPDATE: { |
316 // If there is a manifest specified background page, then shut it down | 323 // If there is a manifest specified background page, then shut it down |
317 // here, since if the updated extension still has the background page, | 324 // here, since if the updated extension still has the background page, |
318 // then it will be loaded from LOADED callback. Otherwise, leave | 325 // then it will be loaded from LOADED callback. Otherwise, leave |
319 // BackgroundContents in place. | 326 // BackgroundContents in place. |
| 327 // We don't call SendChangeNotification here - it will be generated |
| 328 // from the LOADED callback. |
320 const Extension* extension = | 329 const Extension* extension = |
321 content::Details<UnloadedExtensionInfo>(details)->extension; | 330 content::Details<UnloadedExtensionInfo>(details)->extension; |
322 if (extension->has_background_page()) | 331 if (extension->has_background_page()) |
323 ShutdownAssociatedBackgroundContents(ASCIIToUTF16(extension->id())); | 332 ShutdownAssociatedBackgroundContents(ASCIIToUTF16(extension->id())); |
324 break; | 333 break; |
325 } | 334 } |
326 default: | 335 default: |
327 NOTREACHED(); | 336 NOTREACHED(); |
328 ShutdownAssociatedBackgroundContents( | 337 ShutdownAssociatedBackgroundContents( |
329 ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)-> | 338 ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)-> |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 NOTREACHED() << "No extension found for BackgroundContents - id = " | 378 NOTREACHED() << "No extension found for BackgroundContents - id = " |
370 << *it; | 379 << *it; |
371 // Don't cancel out of our loop, just ignore this BackgroundContents and | 380 // Don't cancel out of our loop, just ignore this BackgroundContents and |
372 // load the next one. | 381 // load the next one. |
373 continue; | 382 continue; |
374 } | 383 } |
375 LoadBackgroundContentsFromDictionary(profile, *it, contents); | 384 LoadBackgroundContentsFromDictionary(profile, *it, contents); |
376 } | 385 } |
377 } | 386 } |
378 | 387 |
| 388 void BackgroundContentsService::SendChangeNotification(Profile* profile) { |
| 389 content::NotificationService::current()->Notify( |
| 390 chrome::NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED, |
| 391 content::Source<Profile>(profile), |
| 392 content::Details<BackgroundContentsService>(this)); |
| 393 } |
| 394 |
379 void BackgroundContentsService::LoadBackgroundContentsForExtension( | 395 void BackgroundContentsService::LoadBackgroundContentsForExtension( |
380 Profile* profile, | 396 Profile* profile, |
381 const std::string& extension_id) { | 397 const std::string& extension_id) { |
382 // First look if the manifest specifies a background page. | 398 // First look if the manifest specifies a background page. |
383 const Extension* extension = | 399 const Extension* extension = |
384 profile->GetExtensionService()->GetExtensionById(extension_id, false); | 400 profile->GetExtensionService()->GetExtensionById(extension_id, false); |
385 DCHECK(!extension || extension->is_hosted_app()); | 401 DCHECK(!extension || extension->is_hosted_app()); |
386 if (extension && extension->has_background_page()) { | 402 if (extension && extension->has_background_page()) { |
387 LoadBackgroundContents(profile, | 403 LoadBackgroundContents(profile, |
388 extension->GetBackgroundURL(), | 404 extension->GetBackgroundURL(), |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 // Register the BackgroundContents internally, then send out a notification | 492 // Register the BackgroundContents internally, then send out a notification |
477 // to external listeners. | 493 // to external listeners. |
478 BackgroundContentsOpenedDetails details = {contents, | 494 BackgroundContentsOpenedDetails details = {contents, |
479 frame_name, | 495 frame_name, |
480 application_id}; | 496 application_id}; |
481 BackgroundContentsOpened(&details); | 497 BackgroundContentsOpened(&details); |
482 content::NotificationService::current()->Notify( | 498 content::NotificationService::current()->Notify( |
483 chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, | 499 chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, |
484 content::Source<Profile>(profile), | 500 content::Source<Profile>(profile), |
485 content::Details<BackgroundContentsOpenedDetails>(&details)); | 501 content::Details<BackgroundContentsOpenedDetails>(&details)); |
| 502 |
| 503 // A new background contents has been created - notify our listeners. |
| 504 SendChangeNotification(profile); |
486 return contents; | 505 return contents; |
487 } | 506 } |
488 | 507 |
489 void BackgroundContentsService::RegisterBackgroundContents( | 508 void BackgroundContentsService::RegisterBackgroundContents( |
490 BackgroundContents* background_contents) { | 509 BackgroundContents* background_contents) { |
491 DCHECK(IsTracked(background_contents)); | 510 DCHECK(IsTracked(background_contents)); |
492 if (!prefs_) | 511 if (!prefs_) |
493 return; | 512 return; |
494 | 513 |
495 // We store the first URL we receive for a given application. If there's | 514 // We store the first URL we receive for a given application. If there's |
496 // already an entry for this application, no need to do anything. | 515 // already an entry for this application, no need to do anything. |
497 // TODO(atwilson): Verify that this is the desired behavior based on developer | 516 // TODO(atwilson): Verify that this is the desired behavior based on developer |
498 // feedback (http://crbug.com/47118). | 517 // feedback (http://crbug.com/47118). |
499 DictionaryPrefUpdate update(prefs_, prefs::kRegisteredBackgroundContents); | 518 DictionaryPrefUpdate update(prefs_, prefs::kRegisteredBackgroundContents); |
500 DictionaryValue* pref = update.Get(); | 519 DictionaryValue* pref = update.Get(); |
501 const string16& appid = GetParentApplicationId(background_contents); | 520 const string16& appid = GetParentApplicationId(background_contents); |
502 DictionaryValue* current; | 521 DictionaryValue* current; |
503 if (pref->GetDictionaryWithoutPathExpansion(UTF16ToUTF8(appid), ¤t)) | 522 if (pref->GetDictionaryWithoutPathExpansion(UTF16ToUTF8(appid), ¤t)) |
504 return; | 523 return; |
505 | 524 |
506 // No entry for this application yet, so add one. | 525 // No entry for this application yet, so add one. |
507 DictionaryValue* dict = new DictionaryValue(); | 526 DictionaryValue* dict = new DictionaryValue(); |
508 dict->SetString(kUrlKey, background_contents->GetURL().spec()); | 527 dict->SetString(kUrlKey, background_contents->GetURL().spec()); |
509 dict->SetString(kFrameNameKey, contents_map_[appid].frame_name); | 528 dict->SetString(kFrameNameKey, contents_map_[appid].frame_name); |
510 pref->SetWithoutPathExpansion(UTF16ToUTF8(appid), dict); | 529 pref->SetWithoutPathExpansion(UTF16ToUTF8(appid), dict); |
511 } | 530 } |
512 | 531 |
| 532 bool BackgroundContentsService::HasRegisteredBackgroundContents( |
| 533 const string16& app_id) { |
| 534 if (!prefs_) |
| 535 return false; |
| 536 std::string app = UTF16ToUTF8(app_id); |
| 537 const DictionaryValue* contents = |
| 538 prefs_->GetDictionary(prefs::kRegisteredBackgroundContents); |
| 539 return contents->HasKey(app); |
| 540 } |
| 541 |
513 void BackgroundContentsService::UnregisterBackgroundContents( | 542 void BackgroundContentsService::UnregisterBackgroundContents( |
514 BackgroundContents* background_contents) { | 543 BackgroundContents* background_contents) { |
515 if (!prefs_) | 544 if (!prefs_) |
516 return; | 545 return; |
517 DCHECK(IsTracked(background_contents)); | 546 DCHECK(IsTracked(background_contents)); |
518 const string16 appid = GetParentApplicationId(background_contents); | 547 const string16 appid = GetParentApplicationId(background_contents); |
519 DictionaryPrefUpdate update(prefs_, prefs::kRegisteredBackgroundContents); | 548 DictionaryPrefUpdate update(prefs_, prefs::kRegisteredBackgroundContents); |
520 update.Get()->RemoveWithoutPathExpansion(UTF16ToUTF8(appid), NULL); | 549 update.Get()->RemoveWithoutPathExpansion(UTF16ToUTF8(appid), NULL); |
521 } | 550 } |
522 | 551 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
576 WebContents* new_contents, | 605 WebContents* new_contents, |
577 WindowOpenDisposition disposition, | 606 WindowOpenDisposition disposition, |
578 const gfx::Rect& initial_pos, | 607 const gfx::Rect& initial_pos, |
579 bool user_gesture) { | 608 bool user_gesture) { |
580 Browser* browser = BrowserList::GetLastActiveWithProfile( | 609 Browser* browser = BrowserList::GetLastActiveWithProfile( |
581 Profile::FromBrowserContext(new_contents->GetBrowserContext())); | 610 Profile::FromBrowserContext(new_contents->GetBrowserContext())); |
582 if (!browser) | 611 if (!browser) |
583 return; | 612 return; |
584 browser->AddWebContents(new_contents, disposition, initial_pos, user_gesture); | 613 browser->AddWebContents(new_contents, disposition, initial_pos, user_gesture); |
585 } | 614 } |
OLD | NEW |